DoEvents() hanging



如何删除此问题?我最初认为这个问题与DoEvents有关,但事实并非如此。我已将问题转发至此:http://goo.gl/VpAEK并对问题进行更恰当的描述。

谢谢-我很感激任何关于如何处理这件事的指导。。。


首先,我知道这个问题,因为以前有人问过这个一般概念——我(希望)有一个具体的变体可以问。我还将首先说,我理解使用Application.DoEvents()的具体原因,并向所有人保证,我们尽可能避免使用它,并在整个应用程序中有多个线程解决问题(没有Application.DoEvents()的参与)。

话虽如此,它是框架的的一部分,我认为在某些特定情况下它有它的位置。

我所问的具体情况是一个单线程的情况,纯粹涉及UI,根据定义(据我所知),这是在后台线程中无法完成的。更具体地说,我们在一个表单中加载/配置许多UI元素,有时需要1-2秒才能完成,我希望在这个过程中更新一个标签,指示正在发生的事情。在后台线程中真的没有任何繁重的工作要做——这都是UI。

如果在4个标签文本更改后,我没有Application.DoEvents()调用,则标签不会重新绘制自己。如果有人能在纯UI、单线程环境中提出一种不同的解决方案,我会洗耳恭听的。

问题是,偶尔,在我仍在努力确定的情况下,Application.DoEvents()根本不会返回。

我真的理解所有关于DoEvents()方法的抱怨(大多数都是完全有效的!!)以及它可能引起的各种问题!因此,理想情况下,在不就DoEvents调用的利弊展开激烈辩论的情况下(就像这个话题上几乎所有其他帖子一样)——我想回答的具体问题是——有人能想到DoEvents会挂起的原因吗?(即不返回)?

如果你想讨论DoEvents()调用本身,这里有一个关于其优点和缺点的精彩描述:http://goo.gl/4BtZf

  • 我们的用户报告说,当他们使用该应用程序时,这种情况似乎不会发生,而是只有当他们离开电脑一段时间时才会发生(可能涉及屏幕保护程序?)我们在远程查看客户电脑时更改屏幕分辨率时注意到了这一点
  • 我们有一些用户坚持认为,当应用程序最小化时,这种情况会发生得更多
  • 我们有用户坚持认为,当应用程序最小化时,这种情况会发生得更多,他们在IE和/或outlook中做了一些工作

在内部,我们几乎完全无法复制它,除了今天早上我做了上述所有事情,包括禁用我的网络连接一两分钟,VPNing到服务器几分钟,而我们的应用程序都被最小化了。

在这之后(实际上是我们第一次能够在内部复制它),应用程序挂起,当我连接到进程时,它挂在Application.DoEvents()行上。双线法:

label.Text="Foo";Application.DoEvents();

多个附加测试(试图执行相同的操作)无法重现问题。

有什么建议吗?谢谢


编辑:尝试获得一个专门关于DoEvents的问题的答案是禁忌吗?我对StackOverflow还比较陌生,我只是有点困惑为什么我已经得到了两张反对票。

我在其他线程中多次看到这个问题,并且(至少在我看来,几乎通用的回答只是-不要使用application.DoEvents())。我在最初的问题中特别考虑到了这一点,并解释了我们为什么在这种情况下使用它。同时,我特别想避免再次讨论为什么不应该使用DoEvents。如果有足够多的人认为某件事是个坏主意,那么在stackoverflow上讨论它是否只是禁忌?再说一次,我对这个论坛还比较陌生,正在努力理解这里的礼仪。谢谢

认为利用其他后台线程执行此任务是错误的。如果你想走Application.DoEvents的道路,那没关系。我不会坐在这里告诉你不能使用它,但你至少应该考虑不要使用它作为一种可能的选择。正如您所说,您正在做的是更新大量不同的UI元素。你不是在执行一个UI任务,而是在执行很多(十几、几百、几千,等等)任务。您还有一个单独的任务负责管理所有这些较小的任务。这种对较小任务的管理可以在UI线程或非UI线程中完成。如果在UI线程中执行此操作,则UI将被阻止,直到每个子UI操作都完成为止。如果你有一个非UI线程,它只是作为一个"调度器",添加一些较小的UI任务来完成,那么这些较小的用户界面任务可以独立执行,并允许用户界面在其中一些任务之间做任何事情。

这里有一个例子:

private void button1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        for (int i = 0; i < 10; i++)
        {
            Invoke(new MethodInvoker(() => updateLabel(i)));
            Invoke(new MethodInvoker(() => longerUITask(i)));
        }
    });
}
private void longerUITask(int i)
{
    //do databinding that will take a second or two
    Thread.Sleep(1000);
}
private void updateLabel(int i)
{
    label1.Text = i.ToString();
}

这样做会降低效率吗。是的,会的。你将产生其他线程/任务,管理它们,等等。然而,你所得到的代价是简单有效地保证UI将保持响应。

最新更新