【问题标题】:Invoke calls involving WPF controls hosted with WinForm forms never return调用涉及使用 WinForm 表单托管的 WPF 控件的调用永远不会返回
【发布时间】:2014-07-05 11:05:52
【问题描述】:

我有一个托管多个 WPF 控件的 Windows 窗体程序。它是一个测试执行工具。我们遇到了 Invoke 调用永远不会返回的问题。我们的一位用户编写的其中一项测试计划正在发生这种情况。

问题发生在整个程序的不同调用处。两个例子:

winForm.Invoke(new Action(() => wpfControl.DataContext = something));
Application.Current.Dispatcher.Invoke(new Action(() => result.Container.Clear()));

调用 Invoke 的线程永远不会从 Invoke 返回。我预计 GUI 线程会出现死锁,但 GUI 线程执行得很好。 有趣的是,所有 WinForm 控件都正常运行,但没有 WPF 控件响应用户。 似乎没有其他工作线程被阻塞。

想到两个问题:

  1. 有人有调试建议吗?
  2. 为什么会阻止所有 WPF 控件但所有 WinForm 控件都可以正常工作?

编辑: 我应该提到这可能是某种竞争条件。它很少出现,只有在应用程序正常工作一段时间后才会出现。

【问题讨论】:

  • 我不知道到底发生了什么,但是你在这里的信息太少了。您应该获得 dotpeek 或反射器,并在 WPF 内部“循环”中放置一个断点,并查看它为什么不更新/为什么不调用它。调试中最强大的技术是实际调试内部代码。如果您使用Snoop 工具,我也很想看看会发生什么。
  • 你怎么说所有的 WinForm 控件都表现正常?在您的代码中,如果 winForm.Invoke 没有返回到下一行,则整个应用程序不应响应。
  • 设置DataContext 应该在与创建 WPF 控件的线程相同的线程中完成,您确定是这种情况吗?也可以试试BeginInvoke
  • 你确定 WPF Dispatcher 已经启动了吗?
  • @ChrisEelmaa 您对调试的建议正是我下一步要寻找的。我以前没有调试过内部代码。下次我可以看看这个问题时,我会尝试。它每隔几千小时的应用程序运行时间才会发生一次。如果您将编辑作为答案,我会为其分配赏金。

标签: c# .net wpf multithreading winforms


【解决方案1】:

如果我正确理解了这个问题,那么您有一个托管 WPF 控件的 Windows 窗体。

首先,您为什么要这样做?

Windows 窗体具有窗口控件
WPF 有 WPF 控件。

最近我读到 WPF 可以托管 WF 表单。源代码(C# 中的 Pro WPF 4.5,第 4 版)

如果我没记错的话,WPF 控件在它们自己的线程中运行。与WF控件相反。这可能会锁定 WPF 控件。

铌。 如果人们投反对票,至少有勇气讨论原因。

【讨论】:

  • 1.我们在 Winform 中托管 WPF,因为我们有一个旧的 WinForms 应用程序,它会失去投资来重做 WPF。只有在添加真正使用 WPF 的新功能时,我们才会添加 WPF 控件。 2. 感谢关于 WPF 控件拥有自己的线程的说明。根据仍在工作的 WinForms 东西,这应该是显而易见的。
  • 我的建议是尝试获取我提到的书。它提供了关于 WPF 实际工作方式的真正见解。网上可能有电子书;)
【解决方案2】:

您需要通过控件本身来调用 (dipatch)。

使用此代码wpfControl.InvokeIfRequired(() => wpfControl.DataContext = something); 还有这个wpfControl.InvokeIfRequired((() => result.Container.Clear())

public static void InvokeIfRequired(this DispatcherControl control, Action operation)
{
  if (control.Dispatcher.CheckAccess())
  {
    operation();
  }
  else
  {
    control.Dispatcher.BeginInvoke(DispatcherPriority.Normal, operation);
  }
}

【讨论】:

  • 有趣的是,所有 WinForm 控件都表现正常,但没有 WPF 控件响应用户。直接取自问题。这意味着他已经在正确调用。问题似乎出在其他地方。
  • @Blaatz0r 根据示例,调用是通过表单或应用程序调度程序进行的。其中常识是使用控件本身的调用(使用正确的调度程序)。
  • 问题不在于他调用它的方式。因为它有效。问题在于 WPF 控件的构建方式。
  • @Blaatz0r 我明白你的意思,我的建议只是解决方案的第一步。我同意你的观点,这不是完整的解决方案。
【解决方案3】:

我不知道到底发生了什么,但你这里的信息太少了,无法继续。您应该获取 dotpeek 或反射器,并在 WPF 内部“循环”中放置一个断点,然后查看它为什么不更新/为什么不调用它。

调试中最强大的技术是实际调试内部代码。如果您使用 Snoop 工具,我也很想看看会发生什么。

Invoke 本身是非常解决死锁的好方法。我遇到过自己的死锁,我见过其他人遇到过等等。如果可能的话,看看你是否可以通过BeginInvoke 逃脱。

【讨论】:

  • 这并不能解决我的问题,但它确实回答了我对调试建议的请求。谢谢。
猜你喜欢
  • 2015-06-06
  • 2017-12-06
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 2015-10-08
  • 2011-12-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多