2008-11-25 79 views
4

我正在尋找一種通用的方法來實現長時間操作中的等待屏幕。過去我曾經使用過幾次線程,但是我感覺我實施它的要麼很差,要麼太麻煩(並且複製/粘貼 - 恐怖!)。螺紋加載(等待)屏幕

我想盡可能保持通用和簡單,所以我不需要執行加載BackgroundWorker來處理各種廢話,使事情難以維護。

這是我想做些什麼 - 請注意,這可能會從什麼實際上可能相差/最佳實踐/不管 - 使用VB.NET,框架2.0(所以沒有匿名方法):

Private Sub HandleBtnClick(sender as Object, e as EventArgs) Handles Button.Click 
     LoadingScreen.Show() 

     'Do stuff here, this takes a while!' 
     Dim Result as Object = DoSomethingTakingALongTime(SomeControl.SelectedObject) 

     LoadingScreen.Hide() 

     ProcessResults(Result) 
    End Sub 

該應用程序現在完全是單線程的,因此所有內容都在GUI線程上運行。我需要能夠訪問DoSomethingTakingALongTime()中的對象而不會出現跨線程異常。 GUI線程等待一些方法(需要很長時間)才能完成,而LoadingScreen表單應該保持響應(它是動畫的/有一個進度條/等)。

這是一個可行的/好的方法,還是我看到這種方式太簡單了?關於這件事的最佳做法是什麼?最重要的是:我怎麼能實現這樣一個系統?正如我已經提到,我很少有線程的經驗,所以請溫柔請:-)

回答

4

你的問題是,當你試圖將你的工作線程數據傳遞給你的UI線程時,你得到一個交叉線程異常。你需要做的是檢查InvokeRequired和BeginInvoke來對你的UI設置控件之前這樣你就不會得到錯誤,像這樣:

Private Sub work_CrossThreadEvent(ByVal sender As Object, ByVal e As System.EventArgs) Handles work.CrossThreadEvent 

     If Me.InvokeRequired Then 
      Me.BeginInvoke(New EventHandler(AddressOf work_CrossThreadEvent), New Object() {sender, e}) 
      Return 
     End If 

     Me.Text = "Cross Thread" 

End Sub 

只是改變New EventHandler部分到事件處理程序的使用。

此外我認爲使用後臺工作是不是你的工人類不好的方法, 只需創建一個類爲您的工作,並使用背景工人做線程的東西有點像這樣:

Public MustInherit Class Worker 

    Protected WithEvents worker As BackgroundWorker 

    Public Sub New() 

     worker = New BackgroundWorker() 
     worker.WorkerReportsProgress = True 
     worker.WorkerSupportsCancellation = True 

    End Sub 

    Public Sub Start() 

     If (Not worker.IsBusy AndAlso Not worker.CancellationPending) Then 
      worker.RunWorkerAsync() 
     End If 

    End Sub 

    Public Sub Cancel() 
     If (worker.IsBusy AndAlso Not worker.CancellationPending) Then 
      worker.CancelAsync() 
     End If 
    End Sub 

    Protected MustOverride Sub Work() 

    Private Sub OnDoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork 
     Work() 
    End Sub 

    Public Event WorkCompelted As RunWorkerCompletedEventHandler 
    Private Sub OnRunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted 
     OnRunWorkerCompleted(e) 
    End Sub 
    Protected Overridable Sub OnRunWorkerCompleted(ByVal e As RunWorkerCompletedEventArgs) 
     RaiseEvent WorkCompelted(Me, e) 
    End Sub 

    Public Event ProgressChanged As ProgressChangedEventHandler 
    Private Sub OnProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles worker.ProgressChanged 
     OnProgressChanged(e) 
    End Sub 
    Protected Overridable Sub OnProgressChanged(ByVal e As ProgressChangedEventArgs) 
     RaiseEvent ProgressChanged(Me, e) 
    End Sub 

End Class 

Public Class ActualWork 
    Inherits Worker 

    Public Event CrossThreadEvent As EventHandler 

    Protected Overrides Sub Work() 

     'do work here' 
     WorkABit() 
     worker.ReportProgress(25) 

     WorkABit() 
     worker.ReportProgress(50) 

     WorkABit() 
     worker.ReportProgress(75) 

     WorkABit() 
     worker.ReportProgress(100) 

    End Sub 

    Private Sub WorkABit() 

     If worker.CancellationPending Then Return 
     Thread.Sleep(1000) 
     RaiseEvent CrossThreadEvent(Me, EventArgs.Empty) 

    End Sub 

End Class 

免責聲明..與vb有點生疏,但你應該明白了。

0

在你的線程中,使用Application.Run(yourform)來得到你想要的。

請注意,您需要以某種方式指示表單關閉自己。

+0

哪個線程?該應用程序構建爲單線程(= GUI線程),它已經使用Application.Run來顯示主窗體。 – 2008-11-25 11:06:39

0

我希望你不會覺得這無益 - 但我會問你爲什麼你想要一個線程等待屏幕?首先使用線程的原因是,UI保持響應,並且長時間的操作在後臺完成。否則,你可能只需要在你的FormLoading控件上有一個ProgressBar,並且有DoSomethingTakingALongTime來定期更新它。這根本不需要線程。

+0

對於何時以及如何更新GUI,.NET非常挑剔。有時它運行良好,直到你點擊某處,並完全停止更新。我知道長操作應該在線程而不是GUI中執行,但我沒有提到它,因爲我想知道這個解決方案是否可行。 – 2008-11-25 10:55:39

+0

我真的不關心主窗體,只有加載屏幕應該是響應。我也不關心在哪個線程邏輯執行,但我似乎無法得到它的權利,我總是遇到跨線程異常... – 2008-11-25 10:57:47