4

長時間の操作中に待機画面を実装するための一般的な方法を探しています。以前にスレッド化を数回使用したことがありますが、実装が非常に不十分であるか、または面倒な作業が多すぎると感じています (およびコピー/貼り付け - 恐怖!)。

これを可能な限り汎用的かつシンプルに保ちたいので、BackgroundWorkerあらゆる種類のがらくたを処理する大量の s を実装する必要がなくなり、保守が難しくなります。

これが私がやりたいことです-これは実際に可能なこと/ベストプラクティス/何でも異なる場合があることに注意してください-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フォームは応答性を維持する必要があります (アニメーション化されている/プログレスバーがある/など)。

これは実行可能/良いアプローチですか、それとも単純すぎると思いますか? この問題に関するベストプラクティスは何ですか? そして最も重要なことは、そのようなシステムをどのように実装できるかということです。すでに述べたように、私はスレッディングの経験がほとんどないので、優しくしてください:-)

4

3 に答える 3

4

あなたの問題は、ワーカー スレッド データを 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で少しさびていますが、アイデアを得る必要があります。

于 2008-12-01T13:21:33.117 に答える
0

これが役に立たないことを願っていますが、スレッド化された待機画面が必要な理由は何ですか? そもそもスレッド化を使用する理由は、UI の応答性を維持し、長時間の操作がバックグラウンドで実行されるようにするためです。

それ以外の場合は、FormLoading コントロールに ProgressBar を配置し、DoSomethingTakingALongTime で定期的に更新することもできます。これにはスレッドはまったく必要ありません。

于 2008-11-25T10:41:11.180 に答える
0

スレッドで Application.Run(yourform) を使用して、必要なものを取得します。

何らかの方法でフォームを閉じるように通知する必要があることに注意してください。

于 2008-11-25T10:31:02.290 に答える