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



在我的应用程序中,我调用一个更新软件的进程 - 它存储在自己的类中。即使你,由于某种原因,我也一直在几个地方写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。 它不仅效果较差,还会导致各种意外行为。 在 VB 的 pre-.NET 版本(例如 VB6)中,DoEvents通常是唯一的选择,但在 .NET 中,多线程相对容易。 在某些情况下,DoEvents仍然合法地有用,但它们应该很少而且相距甚远,并且只有在非常谨慎和谨慎的情况下才能实施。

有两种建议的方法可以在 WinForm 应用程序中实现多线程。 原始方法(仍然运行良好)是使用BackgroundWorker组件(您可以在 WinForm 设计器工具箱中找到它)。BackgroundWorker在不同的线程上引发一个事件,以便您可以在该事件处理程序中执行所有长时间运行的工作,而不会阻塞 UI。 然后,当全部完成后,它会在 UI 线程上引发另一个事件,以便你可以在工作完成后更新 UI。

较新的方法更简洁、更易于阅读,但更复杂一些,它是使用AsyncAwait关键字使所有长时间运行的方法以及调用它们的事件处理程序异步。

最新更新