螺纹装载(等待)屏幕

时间:2008-11-25 10:29:21

标签: .net vb.net multithreading screen loading

我正在寻找一种在长时间操作期间实现等待屏幕的通用方法。我以前曾经使用过几次穿线,但我觉得我实现它的效果非常差,或者太麻烦了(复制/粘贴 - 恐怖!)。

我希望尽可能保持通用和简单,因此我不必实现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表格应保持响应(它是动画/有进度条等)。

这是一个可行的/好的方法还是我看到这种方式太简单了?关于这个问题的最佳做法是什么?最重要的是:我怎么能实现这样的系统?正如我已经提到的,我对线程的经验很少,所以请温柔一点: - )

3 个答案:

答案 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定期更新它。这根本不需要线程。