Vb.net 已使用DoEvents,但应用程序没有响应

Vb.net 已使用DoEvents,但应用程序没有响应,vb.net,Vb.net,在我的应用程序中,我调用一个进程来更新存储在自己类中的软件。甚至我也在少数地方编写了Application.DoEvents(),因为某些原因,更新表单中的标签没有更新,表单本身处于非活动状态 Namespace software Public Class updater Public Function UpdateSoftware(ByVal url As String, ByVal downloadFolder As String) As Boolean Ap

在我的应用程序中,我调用一个进程来更新存储在自己类中的软件。甚至我也在少数地方编写了
Application.DoEvents()
,因为某些原因,更新表单中的标签没有更新,表单本身处于非活动状态

Namespace software

Public Class updater 

    Public Function UpdateSoftware(ByVal url As String, ByVal downloadFolder As String) As Boolean 
        Application.DoEvents()
        Thread.Sleep(1000)

        frmUpdate.lblResult.Text = "Update is about to begin"
        Thread.Sleep(1000)
        frmUpdate.lblResult.Text = "Downloading data"
        Thread.Sleep(1000)

        Application.DoEvents()

        frmUpdate.lblResult.Text = "About to start the writing process" 
        Application.DoEvents()

        frmUpdate.lblResult.Text = "Software was updated, please restart your device."
    End Function

End Class

End Namespace

我不明白你为什么要在这些特定的位置调用
DoEvents
,因为它们在哪里都不会产生任何可见的效果。第一种情况发生在任何标签更改之前,因此允许表单刷新没有意义。在所有长期运行的工作都已经完成(三次睡眠)之后,其他人就在最后了。因此,虽然它们允许表单在执行离开方法之前刷新,但它很快就会离开方法,所以在那里也没有意义。唯一可以调用
DoEvents
的地方是在两个长时间运行的东西之间。例如,如果您这样做,您会注意到一个差异:

Public Function UpdateSoftware(ByVal url As String, ByVal downloadFolder As String) As Boolean 
    Thread.Sleep(1000)
    frmUpdate.lblResult.Text = "Update is about to begin"
    Application.DoEvents()

    Thread.Sleep(1000)
    frmUpdate.lblResult.Text = "Downloading data"
    Application.DoEvents()

    Thread.Sleep(1000)
    frmUpdate.lblResult.Text = "About to start the writing process" 
    frmUpdate.lblResult.Text = "Software was updated, please restart your device."
End Function
您需要了解,在.NET WinForms(以及WPF)中,UI是在单个线程上运行的。我的意思是,如果某个事件处理程序包含需要很长时间才能完成的代码,那么UI将在事件处理程序执行的整个时间内冻结。UI刷新将被完全阻止,直到最后一个事件处理程序完成其所做的任何操作
DoEvents
是一种绕过它的黑客方式(而且是一种危险的黑客)。每次调用
DoEvents
,它都会将控件返回到窗体,以处理它排队等待执行的任何其他操作(例如重新绘制屏幕和处理用户输入),然后将执行返回到原始事件处理程序,以便它可以在停止的位置继续。这意味着,每次调用
DoEvents
,它都允许表单在该点重新绘制,但事件处理程序仍然会在所有
DoEvents
之间阻塞UI

正如其他人已经暗示的那样,使用
DoEvents
是非常不鼓励的。它不仅效率较低,还可能导致各种意想不到的行为。在.NET之前版本的VB(例如VB6)中,
DoEvents
通常是唯一的选项,但在.NET中,多线程相对容易。在某些情况下,
DoEvents
仍然合法地有用,但它们应该非常少,而且只能通过实现

在WinForm应用程序中,有两种推荐的实现多线程的方法。最初的方法仍然很有效,就是使用
BackgroundWorker
组件(您可以在WinFormDesigner工具箱中找到)。
BackgroundWorker
在不同的线程上引发一个事件,这样您就可以在该事件处理程序中完成所有长期运行的工作,而不会阻塞UI。然后,当所有这些都完成后,它会引发另一个事件,返回到UI线程,以便您可以在工作完成后更新UI


较新的方法更简洁易读,但更复杂一点,就是使用
Async
wait
关键字使所有长期运行的方法和调用它们的事件处理程序都是异步的。

我不明白为什么要在这些特定位置调用
DoEvents
,因为它们都不会在它们所在的位置产生任何可见的效果。第一种情况发生在任何标签更改之前,因此允许表单刷新没有意义。在所有长期运行的工作都已经完成(三次睡眠)之后,其他人就在最后了。因此,虽然它们允许表单在执行离开方法之前刷新,但它很快就会离开方法,所以在那里也没有意义。唯一可以调用
DoEvents
的地方是在两个长时间运行的东西之间。例如,如果您这样做,您会注意到一个差异:

Public Function UpdateSoftware(ByVal url As String, ByVal downloadFolder As String) As Boolean 
    Thread.Sleep(1000)
    frmUpdate.lblResult.Text = "Update is about to begin"
    Application.DoEvents()

    Thread.Sleep(1000)
    frmUpdate.lblResult.Text = "Downloading data"
    Application.DoEvents()

    Thread.Sleep(1000)
    frmUpdate.lblResult.Text = "About to start the writing process" 
    frmUpdate.lblResult.Text = "Software was updated, please restart your device."
End Function
您需要了解,在.NET WinForms(以及WPF)中,UI是在单个线程上运行的。我的意思是,如果某个事件处理程序包含需要很长时间才能完成的代码,那么UI将在事件处理程序执行的整个时间内冻结。UI刷新将被完全阻止,直到最后一个事件处理程序完成其所做的任何操作
DoEvents
是一种绕过它的黑客方式(而且是一种危险的黑客)。每次调用
DoEvents
,它都会将控件返回到窗体,以处理它排队等待执行的任何其他操作(例如重新绘制屏幕和处理用户输入),然后将执行返回到原始事件处理程序,以便它可以在停止的位置继续。这意味着,每次调用
DoEvents
,它都允许表单在该点重新绘制,但事件处理程序仍然会在所有
DoEvents
之间阻塞UI

正如其他人已经暗示的那样,使用
DoEvents
是非常不鼓励的。它不仅效率较低,还可能导致各种意想不到的行为。在.NET之前版本的VB(例如VB6)中,
DoEvents
通常是唯一的选项,但在.NET中,多线程相对容易。在某些情况下,
DoEvents
仍然合法地有用,但它们应该非常少,而且只能通过实现

在WinForm应用程序中,有两种推荐的实现多线程的方法。最初的方法仍然很有效,就是使用
BackgroundWorker
组件(您可以在WinFormDesigner工具箱中找到)。
BackgroundWorker
在不同的线程上引发一个事件,这样您就可以在该事件处理程序中完成所有长期运行的工作,而不会阻塞UI。然后,当所有这些都完成后,它会引发另一个事件,返回到UI线程,以便您可以在工作完成后更新UI<