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 回答