【问题标题】:WPF Main application stops responding if a child window is being moved around如果正在移动子窗口,WPF 主应用程序将停止响应
【发布时间】:2011-06-01 23:19:43
【问题描述】:

我们有一个使用 WPF 用 C# 编写的应用程序。 它有一个基于计时器的激活事件,会导致在 DirectX 上下文中进行一些绘图。

一切看起来都很好,直到我们打开子窗口,并在屏幕上移动它。时间似乎与计时器被触发的时间一致,但在那一刻,整个屏幕(甚至其他应用程序)似乎都冻结了,用户无法点击任何地方。

如果按下 ALT+TAB 组合键,则正常操作会从冻结的完全相同的点恢复。在冻结状态期间,CPU/内存利用率没有上升,这让我怀疑主线程上存在某种阻塞。

通常,如果我的应用程序在某个操作过程中挂起,我会在 Visual Studio 中按下暂停键,然后在调试器中查看线程视图。这让我充分了解哪个电话是罪魁祸首。

但在这种情况下,如果我按 ALT+TAB 切换到 IDE,我的应用程序会恢复正常执行。如果我将 IDE 放在辅助屏幕上并尝试单击(无需按 ALT+TAB),它似乎也被冻结(正如我之前提到的,整个桌面似乎被鼠标点击冻结。但是鼠标移动是正常)

任何人都面临/知道类似的问题,我该如何继续调试它?

【问题讨论】:

    标签: c# wpf windows directx window


    【解决方案1】:

    问题在于您使用的是单线程。您需要将工作卸载到另一个线程。即:ThreadPool.QueueUserWorkItem 或者使用更新的Task模型,或者Dispatcher.Invoke ...

    只要确保您在完成后将任何 UI 编组回 UI 线程,否则它将在您身上使用 GPF。

    【讨论】:

    • 这是因为后台线程中的代码有一个调用:(dispatcher.Invoke(new Action(delegate { }), DispatcherPriority.Background);。这会导致属性更改通知,嗯,原因进行该调用是为了立即更新 UI。为什么要以仅通过执行 ALT+TAB 才能解决的方式阻止整个应用程序?有什么见解吗?
    • dispatcher.Invoke() 可以阻止。但是,有一个带有超时参数的重载版本,非常方便。还有一个 BeginInvoke,但对我来说,操作要么应该执行,要么叫它退出,所以这就是我使用的。它不再冻结。
    【解决方案2】:

    尝试使用 BackgroundWorker 进程在后台运行您的计时器。我遇到了完全相同的问题,我使用了 BackgroundWorker 并解决了我的问题。这里有一些示例代码可以帮助您入门:

    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
    bw.RunWorkerAsync();
    bw.Dispose();
    
    private void bw_DoWork(object sender, DoWorkEventArgs e)
      {
         //Do Stuff Here            
         return;
      }
    
    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
      {
         //Do an action when complete
      }
    

    只需将其包装在您的计时器滴答事件中,一切都应按需要运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-27
      • 1970-01-01
      • 1970-01-01
      • 2013-07-26
      • 1970-01-01
      相关资源
      最近更新 更多