1

スレッドを使用して、時間のかかる操作 (for ループ) の実行中に進行状況ウィンドウを表示しています。その操作の後、スレッドを停止したいのですが、メソッド " ShowProgressDialog " が呼び出されていません。正常に動作している他のイベント。以下はコードです。

Private Sub TSBRSToLoc_Click(sender As System.Object, e As System.EventArgs) Handles TSBRSToLoc.Click
    Try

        If Not BWRRStoLoc.IsBusy Then
            Dim backgroundThred As New Thread(AddressOf ShowProgressDialog)
            backgroundThred.IsBackground = True
            'Dim formProgree As New ProgressForm
            backgroundThred.Start()
            DisableBtns(sender)
            ProgressBarCompare.Value = 0
            lblProgStatus.Text = ""

            Dim filesSize As Long = 0
            For index As Integer = 0 To ObjlsViewCompare.Items.Count - 1
                Dim file As File = ObjlsViewCompare.GetModelObject(index)
                If Not file.Status = MatchStatus.MisingOnRackSpace Then
                    filesSize = filesSize + file.SizeOnRackSpace
                End If
            Next
            ProgressBarCompare.Maximum = filesSize
            ' formProgree.Close()
            backgroundThred.Abort()
            backgroundThred.Join()
            BWRRStoLoc.RunWorkerAsync()
        End If
    Catch ex As Exception
        MessageBox.Show(ex.Message)
    End Try
End Sub
4

1 に答える 1

1

コードにはいくつかの問題があります。

1: ほとんど呼び出したくないThread.Abort- 特にあるスレッドが別のスレッドを終了する場合、そうすると予測できない影響が生じる可能性があります。詳細については、MSDN を参照してください。

スレッドをシャットダウンする正しい方法は、ある種のメッセージを使用して、スレッドにそれ自体で終了するように指示することです。静的変数を設定する (スレッドが定期的にチェックする)、同期オブジェクトを使用するなどThread.Abort()は、絶対にダメです。

2: ロジックが逆になっています。メイン スレッドに時間のかかる操作があり (ボタン クリック イベント ハンドラーは、これがメインの UI スレッドであることを示しています)、バックグラウンド スレッドから進行状況ダイアログを表示しようとしています。

逆に、クリック ハンドラー内でバックグラウンド処理用のすべてのデータを設定し、進行状況ダイアログを表示して (モードレスであると仮定)、処理を行うバックグラウンド スレッドを開始する必要があります。

処理中、バックグラウンド スレッドは進行状況ウィンドウにその進行状況を通知し続け、完了すると進行状況ウィンドウにもこの事実を通知する必要があります。

UI スレッドに通知する必要がある場合はいつでも、正しいスレッドへの呼び出しを適切にマーサルする必要があります。これは、どの UI 要素もそれを作成したスレッドからのみアクセスできるためです。たとえば、呼び出しをマーシャリングせずにワーカー スレッドからラベル コントロールのテキストを設定することはできません。

マーシャリングにはInvokeRequired/を使用する必要があります。BeginInvoke()呼び出すBeginInvoke()ときは、デリゲートを渡します。このようなもの (C# 構文については申し訳ありません。私は VB.NET に精通していません。これを移植するのは簡単なはずです):

private void SomeEventHandler ( object oSender, EventArgs oE )
{
    if ( InvokeRequired )
    {
        MethodInvoker oDelegate = (MethodInvoker) delegate
        {
            SomeEventHandler ( oSender, oE );
        };

        BeginInvoke ( oDelegate );
        return;
    }
    else
    {
        // already on the correct thread; access UI controls here
    }
}

これはすべて、コントロールがメッセージを介してプロパティの更新の多くを処理し、それらのメッセージを正しい順序で同期的に配信する必要があるためです。これを確実にする唯一の方法は (非常に複雑なコーディングを行わなくても)、スレッドがメッセージ ポンプを実行する同じスレッド上にすべてのコントロールを作成することです。

メイン UI スレッド以外のスレッドで UI を作成する方法の詳細については、この質問を参照してください。(可能ですが、本当に本当に必要な場合にのみこれを行いたいと思います。それはかなりまれです。)

于 2013-01-04T03:28:42.857 に答える