Application.DoEvents()可以在c#中使用吗?
这个函数是一种让GUI赶上应用程序其余部分的方法吗,就像VB6的DoEvents一样?
Application.DoEvents()可以在c#中使用吗?
这个函数是一种让GUI赶上应用程序其余部分的方法吗,就像VB6的DoEvents一样?
当前回答
请查阅应用程序的MSDN文档。DoEvents方法。
其他回答
请查阅应用程序的MSDN文档。DoEvents方法。
根据我的经验,我建议在。net中使用DoEvents时要非常谨慎。当在包含DataGridViews的TabControl中使用DoEvents时,我经历了一些非常奇怪的结果。另一方面,如果你所处理的只是一个带有进度条的小表单,那么它可能是OK的。
底线是:如果要使用DoEvents,那么在部署应用程序之前需要彻底测试它。
我见过许多使用“DoEvents-Hack”的商业应用程序。特别是当渲染开始发挥作用时,我经常看到这样的情况:
while(running)
{
Render();
Application.DoEvents();
}
他们都知道这种方法的害处。然而,他们使用黑客,因为他们不知道任何其他解决方案。以下是Tom Miller的博客文章中的一些方法:
Set your form to have all drawing occur in WmPaint, and do your rendering there. Before the end of the OnPaint method, make sure you do a this.Invalidate(); This will cause the OnPaint method to be fired again immediately. P/Invoke into the Win32 API and call PeekMessage/TranslateMessage/DispatchMessage. (Doevents actually does something similar, but you can do this without the extra allocations). Write your own forms class that is a small wrapper around CreateWindowEx, and give yourself complete control over the message loop. -Decide that the DoEvents method works fine for you and stick with it.
Hmya, DoEvents()的持久神秘感。有很多人反对它,但没有人真正解释为什么它是“坏的”。这和“不要改变结构体”是一样的道理。嗯,为什么运行时和语言支持突变一个结构,如果这是如此糟糕?同样的原因:如果你做得不对,你就搬起石头砸自己的脚。很容易。正确地执行它需要确切地知道它做什么,在DoEvents()的情况下,这绝对不容易理解。
马上:几乎所有Windows窗体程序实际上都包含对DoEvents()的调用。它被巧妙地伪装了,但是使用了不同的名称:ShowDialog()。DoEvents()允许对话框是模态的,而不会冻结应用程序中的其他窗口。
大多数程序员在编写自己的模态循环时都希望使用DoEvents来防止用户界面冻结。它确实做到了;它分派Windows消息,并获得任何油漆请求交付。但问题是,这并不是有选择性的。它不仅发送油漆消息,还传递其他所有信息。
还有一组会引起麻烦的通知。它们来自显示器前大约3英尺的地方。例如,用户可以在调用DoEvents()的循环运行时关闭主窗口。这是可行的,用户界面消失了。但是你的代码并没有停止,它仍然在执行循环。这是不好的。非常非常糟糕。
还有更多:用户可以单击相同的菜单项或按钮,从而启动相同的循环。现在有两个嵌套循环执行DoEvents(),前一个循环暂停,新循环从头开始。这可能会起作用,但可能性很小。特别是当嵌套循环结束,挂起的循环继续时,试图完成已经完成的工作。如果没有异常爆炸,那么数据肯定被打乱了。
Back to ShowDialog(). It executes DoEvents(), but do note that it does something else. It disables all the windows in the application, other than the dialog. Now that 3-feet problem is solved, the user cannot do anything to mess up the logic. Both the close-the-window and start-the-job-again failure modes are solved. Or to put it another way, there is no way for the user to make your program run code in a different order. It will execute predictably, just like it did when you tested your code. It makes dialogs extremely annoying; who doesn't hate having a dialog active and not being able to copy and paste something from another window? But that's the price.
Which is what it takes to use DoEvents safely in your code. Setting the Enabled property of all your forms to false is a quick and efficient way to avoid problems. Of course, no programmer ever actually likes doing this. And doesn't. Which is why you shouldn't use DoEvents(). You should use threads. Even though they hand you a complete arsenal of ways to shoot your foot in colorful and inscrutable ways. But with the advantage that you only shoot your own foot; it won't (typically) let the user shoot hers.
c#和VB的下一个版本。NET将使用新的await和async关键字提供一个不同的枪。这在很小程度上是受到DoEvents和线程引起的麻烦的启发,但在很大程度上是受到WinRT的API设计的启发,它要求您在异步操作发生时保持UI的更新。比如从文件中读取。
我看到了上面jheriko的评论,最初我同意,如果你最终旋转你的主UI线程,等待另一个线程上长时间运行的异步代码来完成,我无法找到一种避免使用DoEvents的方法。但是根据Matthias的回答,我的UI上一个小面板的简单刷新可以取代DoEvents(并避免一个讨厌的副作用)。
更多关于我案子的细节…
我正在做以下(在这里建议),以确保进度条类型的启动屏幕(如何显示“加载”覆盖…)在长时间运行SQL命令期间更新:
IAsyncResult asyncResult = sqlCmd.BeginExecuteNonQuery();
while (!asyncResult.IsCompleted) //UI thread needs to Wait for Async SQL command to return
{
System.Threading.Thread.Sleep(10);
Application.DoEvents(); //to make the UI responsive
}
缺点:对我来说,调用DoEvents意味着鼠标点击有时会触发启动画面后面的表单,即使我把它设置为TopMost。
好的/答案:用一个简单的刷新调用替换DoEvents行到我的启动画面中心的一个小面板,FormSplash.Panel1.Refresh()。UI更新得很好,其他人警告过的DoEvents怪异现象也消失了。