在我的应用程序中,我调用了一个更新软件的过程-该过程存储在其自己的类中。甚至出于某种原因,即使您在几个地方都写过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
答案 0 :(得分:6)
我不知道您为什么在这些特定位置致电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
某种程度上是解决该问题的一种hack方法(并且是一种危险的hack)。每次调用DoEvents
时,它将控制权返回到表单以处理其排队等待做的其他事情(例如重新绘制屏幕和处理用户输入),然后将执行返回给原始事件处理程序,以便它可以从中断处继续。这意味着,每次您调用DoEvents
时,它都可以在那一刻重新绘制窗体,但是事件处理程序仍会在所有DoEvents
之间阻塞UI。
正如其他人已经暗示的那样,强烈建议不要使用DoEvents
。它不仅效率较低,而且可能导致各种意外行为。在.NET之前的VB版本(例如VB6)中,DoEvents
通常是唯一的选择,但是在.NET中,多线程相对容易。在某些情况下,DoEvents
依旧仍然有用,但是它们应该很少而且相距甚远,只能使用great care and caution来实现。
有两种推荐的在WinForm应用程序中实现多线程的方法。仍然有效的原始方法是使用BackgroundWorker
组件(您可以在WinForm设计器工具箱中找到它)。 BackgroundWorker
在另一个线程上引发一个事件,以便您可以在该事件处理程序中完成所有长时间运行的工作,而不会阻塞UI。然后,当所有操作完成后,它将引发另一个事件,返回UI线程,以便您可以在工作完成后更新UI。
较新的方法更简洁易读,但更为复杂,它是使用Async
和Await
关键字来创建所有长期运行的方法和事件调用它们的处理程序,是异步的。