使用Dispatcher.PushFrame和Application.DoEvents在UI线程中进行相互独占操作

时间:2014-03-14 12:01:55

标签: c# .net wpf user-interface dispatcher

情况

我将尝试用一个小例子来解释我的问题。我有一个管理视图堆栈的类。替换视图显示并初始化它们等。

class ViewManager()
{
    void ReplaceView()
    {
        RemoveView(...);
        InitializeView(...); // this code may call Application.DoEvents()
        AddNewView(...);
    }

    void ShowModalView()
    {
        ShowView();
        Dispatcher.PushFrame()
        ....
        // wait until view can be removed
        RemoveView();
    }

   void RemoveView()
   {
     ...
   }
   // ... more functions
}

因为ViewManager对UI元素做了很多工作,所以其他线程使用ViewManager到Dispatcher.Invoke。

Dispatcher.Invoke(new Action(() => m_viewManager.Remove(someView)));

如果现在多个线程在ViewManager上调用操作,并且其中一个线程在代码Application.DoEvents或DispatcherPushFrame中的某处深入调用,则会生成第二个MessageLoop,它将调用视图管理器中的另一个方法。

问题:

  • 调用ShowModalView并调用PushFrame。
  • 在ShowModalView期间,另一个线程调用ShowModalView或ReplaceView。
  • 因为新的消息循环执行排队到调度程序的所有任务,所以也会执行此方法。
  • 因此,ViewManager的两个方法“同时”执行 - 或者更好,因为它是相同的线程 - 彼此嵌套。

锁定ViewManager内部是没用的,因为它是完全相同的线程。信号量可能会冻结UI线程,因为在“ShowModalView”的Message循环期间,另一个线程可以在调度程序上调用ShowModalView,这将冻结UI线程。

问题:

  • 在“ShowModalView”期间,UI线程应处理输入/绘制等,但不应处理通过“Dispatcher.Invoke”调用的其他任务这可能吗?
  • 你还有其他想法来解决这个问题吗?

感谢您的提示和答案

曼努埃尔

修改 一种解决方案可能是摆脱所有DoEvents和PushFrame代码。这很难实现,但可能是唯一正确的解决方案。这篇文章解释了我的问题的一部分

Use of Application.DoEvents

1 个答案:

答案 0 :(得分:0)

正如Servy所说,摆脱Application.DoEvents()和Dispatcher.PushFrame是唯一干净的解决方案。有时这会导致很多重构,但值得付出努力。