我正在寻找一种在长时间操作期间实现等待屏幕的通用方法。我以前曾经使用过几次穿线,但我觉得我实现它的效果非常差,或者太麻烦了(复制/粘贴 - 恐怖!)。
我希望尽可能保持通用和简单,因此我不必实现BackgroundWorker
处理各种废话的负载,使得难以维护。
这就是我想做的事情 - 请注意这可能与实际可行/最佳实践/无论什么不同 - 使用VB.NET,Framework 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
表格应保持响应(它是动画/有进度条等)。
这是一个可行的/好的方法还是我看到这种方式太简单了?关于这个问题的最佳做法是什么?最重要的是:我怎么能实现这样的系统?正如我已经提到的,我对线程的经验很少,所以请温柔一点: - )
答案 0 :(得分:4)
您的问题是,当您尝试将Worker线程数据传递到您的ui线程时,您会遇到跨线程异常。您需要做的是在设置ui上的控件之前检查InvokeRequired并begininvoke,这样就不会出现如下错误:
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,但你应该明白。
答案 1 :(得分:0)
在你的主题中,使用Application.Run(yourform)来获得你想要的东西。
请注意,您需要以某种方式发信号通知表格。
答案 2 :(得分:0)
我希望你没有发现这无益 - 但我会问为什么你想要一个线程等待屏幕?首先使用线程的原因是UI保持响应,并且在后台进行长时间的操作。
否则,你可能只在FormLoading控件上有一个ProgressBar,并让DoSomethingTakingALongTime定期更新它。这根本不需要线程。