Application.DoEvents()可以在c#中使用吗?

这个函数是一种让GUI赶上应用程序其余部分的方法吗,就像VB6的DoEvents一样?


当前回答

DoEvents确实允许用户单击或键入并触发其他事件,后台线程是一种更好的方法。

但是,在某些情况下,您可能会遇到需要刷新事件消息的问题。我遇到了一个问题,在RichTextBox控件忽略ScrollToCaret()方法时,该控件在队列中有消息要处理。

下面的代码在执行DoEvents时阻塞所有用户输入:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Integrative.Desktop.Common
{
    static class NativeMethods
    {
        #region Block input

        [DllImport("user32.dll", EntryPoint = "BlockInput")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool BlockInput([MarshalAs(UnmanagedType.Bool)] bool fBlockIt);

        public static void HoldUser()
        {
            BlockInput(true);
        }

        public static void ReleaseUser()
        {
            BlockInput(false);
        }

        public static void DoEventsBlockingInput()
        {
            HoldUser();
            Application.DoEvents();
            ReleaseUser();
        }

        #endregion
    }
}

其他回答

我见过许多使用“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.

根据我的经验,我建议在。net中使用DoEvents时要非常谨慎。当在包含DataGridViews的TabControl中使用DoEvents时,我经历了一些非常奇怪的结果。另一方面,如果你所处理的只是一个带有进度条的小表单,那么它可能是OK的。

底线是:如果要使用DoEvents,那么在部署应用程序之前需要彻底测试它。

我看到了上面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怪异现象也消失了。

Yes, there is a static DoEvents method in the Application class in the System.Windows.Forms namespace. System.Windows.Forms.Application.DoEvents() can be used to process the messages waiting in the queue on the UI thread when performing a long-running task in the UI thread. This has the benefit of making the UI seem more responsive and not "locked up" while a long task is running. However, this is almost always NOT the best way to do things. According to Microsoft calling DoEvents "...causes the current thread to be suspended while all waiting window messages are processed." If an event is triggered there is a potential for unexpected and intermittent bugs that are difficult to track down. If you have an extensive task it is far better to do it in a separate thread. Running long tasks in a separate thread allows them to be processed without interfering with the UI continuing to run smoothly. Look here for more details.

下面是如何使用DoEvents的示例;请注意,微软也提供了使用它的警告。

请查阅应用程序的MSDN文档。DoEvents方法。