2011-07-15 62 views
1

話題大家好,我搜索了大量本,但無法找到真正適合這種情況的結果。Vb.net WinForm的更新GUI調用

我有一個(當前)單線程寫入VB.Net應用的主要處理步驟12以樹狀控制檢查列表項。該程序依次執行步驟(函數和存儲過程)並在繼續之前檢查結果。

步驟(大大簡化)是:從一個txt文件 1.導入數據 2.大容量插入到數據庫中 3.做一些處理 4.使用數據跨檢索更多的相關數據來自鏈接服務器的複雜聯接中的網絡。 5.更新的結果 6本地數據庫做更多的處理 7.將最終結果到不同的數據庫不同的服務器上。

我不會進入所有必須以此方式完成的原因(公司內部不同的服務器所有者,服務器之間缺乏信任,只能訪問某些數據庫等),但問題在於步驟4.

根據(外部)服務器上的處理負載和導入文件中的數據量,此步驟可能需要1-1/2小時才能執行。由於這是一個單線程應用程序,gui凍結等待從鏈接服務器檢索數據。

除了桌面上的灰塊(由於沒有GUI更新)程序運行完全。

嘗試的解決方案: 1)我嘗試了一個計時器的建議刷新表單沒有成功。

2)我一直在使用後臺工作進程嘗試,但不能讓應用程序等待結果的程序繼續之前。

3)I也試圖與沒有成功穿線的不同示例。所有其他步驟完成得如此之快,以至於gui從不釋放,但我不會反對在此應用程序中線程化所有的sql調用。

在我這麼做的時候,這是我第一次無法在網上找到解決方案,而且之前從未需要發佈,所以對此事的幫助將不勝感激。

--edit

這裏是我的嘗試: 謝謝你的快速反應。

我使用這裏描述的過程:http://midnightprogrammer.net/post/Using-Background-Worker-in-C.aspx(將其轉換爲vb.net後)。但是該程序正好經過該步驟(情況Node6處於底部)。

Imports System.Runtime.InteropServices 
Imports System.Threading 
Imports System.ComponentModel 

Private Sub bgw_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) 
     'Report progress bar change  
     progress.Value = e.ProgressPercentage 

    End Sub 
Private Sub bgw_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) 
    If (e.Cancelled) Then 
     WriteStatus("Operation Cancelled") 
     bRetval = False 
    Else 
     WriteStatus("Operation Completed") 
     bRetval = True 
    End If 

End Sub 


'Background worker DoWork method. Here we will perform our heavy duty tasks. 
Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) 

    Dim Sql As String = "Get_ALS_Data" 
    Dim cmd As New SqlCommand(Sql, ConnLocal) 
    cmd.CommandTimeout = 9000 ' 2 and a half hours 
    Try 
     Dim i As Integer = 0 
     ConnLocal.Open() 

     'ImportRowCount = cmd.ExecuteScalar() 
     Dim dr As SqlDataReader 
     dr = cmd.ExecuteReader() 
     While dr.Read() 
      i = i + 1 
      'report to the backgroundworkerprogress.changed event of the background worker class 
      bgw.ReportProgress(i) 
      Thread.Sleep(1) 
      'Call and check if the cancellation of the operation is pending. If returned true   
      'DoWorkEventArgs object cancels the operation.   
      If bgw.CancellationPending Then 
       e.Cancel = True 
       Return 
      End If 
      ImportRowCount = CInt(dr(0)) 
     End While 

    Catch ex As Exception 
     WriteStatus("Get ALS Data error: " & ex.Message) 
     e.Cancel = True 
     Return 
    Finally 
     ConnLocal.Close() 
    End Try 

    WriteStatus("Get ALS Data completed successfully.") 
    e.Cancel = False 
    Return 


End Sub 

Private Sub bgw_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) 
    'Report progress bar change  
    progress.Value = e.ProgressPercentage 

End Sub 

Private Sub bgw_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) 
    If (e.Cancelled) Then 
     WriteStatus("Operation Cancelled") 
     bRetval = False 
    Else 
     WriteStatus("Operation Completed") 
     bRetval = True 
    End If 

End Sub 

Private Sub ProcessCheckedNodes(ByVal parentNode As TreeNode) 
    Dim Success As Boolean = False 
    For Each childNode As TreeNode In parentNode.Nodes 
     ProgBar += BarSeg 
     If ProgBar > 100 Then 
      ProgBar = 100 
     End If 
     pb1.Value = ProgBar 
     Me.Refresh() 
     If childNode.Checked Then 
      Select Case childNode.Name 
       Case "Node1" 
        '1. Clear local work tables 
        SetChild(childNode, "True") 
        Success = DoCleanup() 
        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 

        SetChild(childNode, "False") 
       Case "Node2" 
        '2. Clear Server Intake table 
        SetChild(childNode, "True") 
        Success = TruncateInserts("DoCleanUp") 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       Case "Node3" 
        '3. Load the temp table 
        SetChild(childNode, "True") 
        Success = LoadMyTempTable() 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       Case "Node4" 
        '4. Load the data from the temp table to the local database 
        SetChild(childNode, "True") 
        Success = BulkCopy_Intake() 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       Case "Node5" 
        '5. Get Intake Dup's 
        SetChild(childNode, "True") 
        Success = GetIntakeDups() 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       **Case "Node6" 
        '6. Get the matching data from the ALS database 
        SetChild(childNode, "True") 
        'Success = GetALS_Data() 
        bgw.RunWorkerAsync() 
        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False")** 
       Case "Node7" 
        '7. Get Core Dup's 
        SetChild(childNode, "True") 
        Success = GetCoreDups() 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       Case "Node8" 
        '8. Process 
        SetChild(childNode, "True") 
        Success = Process() 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       Case "Node9" 
        '9. Export NotFound 
        SetChild(childNode, "True") 
        Success = ExportNotFound() 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       Case "Node10" 
        '10. Move Inserts 
        SetChild(childNode, "True") 
        Success = MoveInserts() 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       Case "Node11" 
        '11. Backup 
        SetChild(childNode, "True") 
        Success = Backup() 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       Case "Node12" 
        SetChild(childNode, "True") 
        'Success = LoadDc() 

        If Success <> True Then 
         SetChild(childNode, "Error") 
         Cursor = Cursors.Default 
         Exit Sub 
        End If 
        SetChild(childNode, "False") 
       Case Else 
        'Ignore it 
      End Select 
     Else 
      childNode.ImageIndex = 0 
      childNode.SelectedImageIndex = 0 
     End If 
     ProcessCheckedNodes(childNode) 
    Next 
    pb1.Value = 100 
End Sub**strong text** 


Public Function GetALS_Data() As Boolean 

    'refresh the form while waiting for the ALS data 
    Dim sAcct As String = "" 

    Dim Sql As String = "Get_ALS_Data" 
    Dim cmd As New SqlCommand(Sql, ConnLocal) 
    cmd.CommandTimeout = 9000 ' 2 and a half hours 
    Try 
     ConnLocal.Open() 
     ImportRowCount = cmd.ExecuteScalar() 
    Catch ex As Exception 
     WriteStatus("Get ALS Data error: " & ex.Message) 
     Return False 
    Finally 
     ConnLocal.Close() 
    End Try 

    WriteStatus("Get ALS Data completed successfully.") 
    Return True 

End Function 
+0

當涉及到WinForms時,後臺工作者是最明顯的路由。你有什麼困難讓你的應用程序等待? –

+0

後臺工作者的要點是應用程序不會等待。如果這樣做,它不會解決你的任何問題。 – rerun

回答

1

不知道爲什麼你的後臺線程你沒有工作,但如果你有一個原因的問題或其他你可以嘗試此解決方案。可能會有點矯枉過正,但它會起作用。

那麼你可能要考慮是使用Syncevents進程和隊列同步模式。如果您要將所有項目都放入隊列FIFO模型中,並使用它們從後臺線程中進行操作,則可以執行所有您正在討論的內容並維護一個可用的UI,使其可以取消等。對此的一個好處是沒有超時在您的數據庫調用或其他項目,但不是線程。

我的代碼是在C#中,但你可以得到圖片。你也可以看看這個EventHandle進程的信息:MSDN - EventWaitHandle

我還沒有測試過,因爲我剛剛輸入了它,但是我們在使用這種類型的內部排隊模型的應用程序,它工作非常以及在後臺處理數據併爲長時間運行和可取消操作維護響應式用戶界面。如果你想取消操作,只需設置ExitThreadEvent即可。希望這可能會給你一些額外的嘗試路徑。

創建SyncEvent類

public class SyncEvents 
{ 
    private EventWaitHandle _newItemEvent; 

private EventWaitHandle _exitThreadEvent; 
private WaitHandle[] _eventArray; 

public SyncEvents() 
{ 
    _newItemEvent = new AutoResetEvent(false); 
    _exitThreadEvent = new ManualResetEvent(false); 
    _eventArray = new WaitHandle[2]; 
    _eventArray[0] = _newItemEvent; 
    _eventArray[1] = _exitThreadEvent; 
} 

public EventWaitHandle ExitThreadEvent 
{ 
    get { return _exitThreadEvent; } 
} 

public EventWaitHandle NewItemEvent 
{ 
    get { return _newItemEvent; } 
} 

public WaitHandle[] EventArray 
{ 
    get { return _eventArray; } 
} 
} 

使用隊列對象,你可以創建一個類指令做你的工作,像這樣與參與以及線程創建一個類。

public class RunItem 
{ 

public int SequenceToRun { get; set; } 

} 

public class ItemRunner 
{ 

private SyncEvents _syncEvents; 
private Queue<RunItem> _items; 
private Thread _processThread; 

public ItemRunner(SyncEvents events, Queue<RunItem> items) 
{ 
    this._syncEvents = events; 
    this._items = items; 
} 

public void Start() 
{ 
    this._processThread = new Thread(this.Run); 
    this._processThread.IsBackground = true; 
    this._processThread.Start(); 
} 

private void Run() 
{ 
    try 
    { 
      while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1) 
      { 
       RunItem item = null; 

       lock (this._items) 
       { 
        if (this._items.Count > 0) 
        { 
         item = this._items.Dequeue(); 
         if (item != null) 
         this.ProcessItem(item); 
         this._syncEvents.NewItemEvent.Set(); 
        } 
        else 
        { 
         this._syncEvents.ExitThreadEvent.Set(); 
        } 

       } 
      } 
    } 
    catch (Exception ex) 
    { 
     // do something to log your exception here 
     // you should have the try catch since you are running in a thread and if it 
     // throws an exception it could kill your entire app. 

    } 
} 

private void ProcessItem(RunItem item) 
{ 
     // Do your item processing here. 
    // You could have a final item that executes the 
    // this._syncEvents.ExitThreadEvent.Set(); so that it actually will stop waiting 

} 
}