4

我有一个简单的“工作”表单,它在自己的线程上运行,让用户知道应用程序在长时间运行的操作中没有死机。为了让工作表格更新,我必须插入一个DoEvents()电话。

我很好奇,这只会为我所在的当前线程发送消息,还是会为整个应用程序发送消息?我希望主窗口在操作完成之前保持无响应,所以我对这种行为很好奇。下面是工作表单的代码。

为了清楚起见,我对我的代码很好,但我想知道DoEvents()线程的行为。

    Public Class frmWorking

    ''' <summary>
    ''' Creates and starts a new thread to handle the Working Dialog
    ''' </summary>
    ''' <returns>The thread of the Working dialog.</returns>
    ''' <remarks></remarks>
    Public Shared Function StartWait() As WorkingFromToken
        Dim th As New Threading.Thread(AddressOf ShowWait)
        Dim token As New WorkingFromToken
        th.Start(token)
        Return token
    End Function

    Private Shared Sub ShowWait(token As WorkingFromToken)
        Dim frm As New frmWorking
        Try
            frm.Show()
            Do
                If frm.txtWait.Text.Length > 45 Then
                    frm.txtWait.Text = "Working"
                Else
                    frm.txtWait.Text &= "."
                End If
                Windows.Forms.Application.DoEvents()
                Threading.Thread.Sleep(250)
            Loop While token.Running
            frm.Hide()

        Catch ex As Threading.ThreadAbortException
            Threading.Thread.ResetAbort()
            frm.Hide()
            Return
        End Try

    End Sub

End Class
4

2 回答 2

3

DoEvents只会抽出当前的 UI 线程。

但是,我不推荐您的方法。

相反,您应该在后台线程上进行工作,并在 UI 线程上显示模态进度表单并使用BeginInvokeBackgroundWorker.

于 2011-06-07T14:46:34.423 回答
2

DoEvents只会影响调用它的线程。它将使发布到该线程的所有 Windows 消息出列并相应地调度它们。发送完所有消息后,它将返回给调用者。

不过,我对您的代码还有其他一些观察。

  • DoEvents通过在循环中重复调用,您基本上已经创建了自己的消息循环的残缺版本。最好只是调用Application.Run来启动一个完整的消息循环。
  • 在主 UI 线程之外的线程上创建消息循环很少是一个好主意。有一些奇怪的事情发生,很难处理。例如,一个线程的模态对话框可能与另一个线程的模态对话框重叠。
  • ThreadAbortException在大多数情况下,试图抓住 a是没有意义的。如果您遇到此异常,则可能(甚至可能)整个 AppDomain 的状态已损坏。与其试图优雅地处理它,不如拆除应用程序域。这是因为异常可以在线程执行期间的任何时候注入,并且这些注入点可能在中间或写入、冗长的操作或其他一些不安全点。
  • 作为上述一点的推论,不要使用Thread.Abort终止另一个线程。有太多太多的事情可能出错。最好使用更安全的机制使线程优雅地结束。
于 2011-06-07T17:28:42.233 回答