【问题标题】:Invalid Window Handle when closing a WinForm that hosts a WPF UserControl that hosts a Windows Forms control关闭承载 Windows 窗体控件的 WPF UserControl 的 WinForm 时窗口句柄无效
【发布时间】:2019-04-07 03:59:53
【问题描述】:

我有一个程序是由一群不同的人在许多不同的年份制作的。有些应用程序是用 Winforms 编写的,有些是用 WPF 编写的。我有一个在某些窗口 (WPF) 中使用的 WPF 用户控件,我正试图将它放入我的程序的 Winforms 窗口之一。我有这个控件的 WPF 和 WinForms 版本,与我的新 WPF 版本相比,WinForms 非常复杂且有些错误,这就是为什么我将它放入旧版 WinForms 窗口的原因。

这个 WPF 用户控件内部有一个 WinForms 控件,因为我找不到我需要的控件的 WPF 版本(一个 hexbox)。在我的 winforms 表单中,我放置了一个托管此 UserControl(WPF) 的 ElementHost。它工作得很好,直到我关闭窗口,也就是当我收到一个 Win32Exception 说 InvalidWindowHandle 时。没有有用的堆栈跟踪。

当我关闭表单时,我处理了解释器WPF,它的元素宿主。在处理解释器WPF时,它会依次处理十六进制框和WinFormHostedControl。

  • interpreterWPF:WPF 用户控件
  • 解释器WPFElementHost:WinFormsElementHost
  • PathfindingEditor:承载所有这些的 WinForms 表单

当我关闭 PathfindingEditor 时,我正在处理许多东西以防止内存泄漏。

(pathfindingeditor.cs)
private void PathfindingEditor_FormClosing(object sender, FormClosingEventArgs e)
        {
            //Nullify things to prevent memory leaks
            interpreterWPF.Dispose();
            interpreterWPFElementHost.Child = null;
            interpreterWPFElementHost.Dispose();
            ...
(interpreterwpf.xaml.cs)
public override void Dispose()
        {
            Interpreter_Hexbox = null;
            Interpreter_Hexbox_Host.Child.Dispose();
            Interpreter_Hexbox_Host.Dispose();
        }

我不确定此时还能做什么。取代 winforms 控件的新 WPF 控件更简单,错误更少。将旧表单更改为 WPF 会很棒,但我还没有找到合适的库来处理它需要执行的复杂任务,而且 WPF 中的 Winforms 托管元素有很多缺点,这就是为什么我不会比 hexbox 更进一步.

我已经阅读了 Dispatcher.InvokeShutdown() 但这似乎完全关闭了 WPF UI 线程。我怀疑这就是我要找的。​​p>

【问题讨论】:

  • 不要给null设置任​​何东西。只需Dispose。我并不是说这会解决问题,但它本身就是一个问题。

标签: c# .net wpf winforms


【解决方案1】:

尝试将 ElementHost 的 WPF 根元素的 AutomationProperties.NameProperty 设置为一些有效的字符串,例如如下:

elementHost.HandleCreated += delegate(object sender, EventArgs e)
                             {
                                 HwndSource source = (HwndSource)HwndSource.FromVisual(elementHost.Child);
                                 AutomationProperties.SetName(source.RootVisual, "elementHost");
                             };

在附加 Visual Studio 调试器时,我收到了以下异常,调用堆栈非常短:

Source "WindowsBase" StackTrace "at MS.Win32.UnsafeNativeMethods.GetWindowText(HandleRef hWnd, StringBuilder lpString, Int32 nMaxCount)"

没有调试器,异常是不可见的。

该异常是从 WPF 框架方法 System.Windows.Automation.Peers.GenericRootAutomationPeer.GetNameCore 内部引发的,因为 ElementHost 的 WPF 部分的已处置窗口句柄 base.Hwnd 在方法中使用如下:

namespace System.Windows.Automation.Peers // from PresentationCore.dll
{
public class GenericRootAutomationPeer : UIElementAutomationPeer
{
    ...
    protected override string GetNameCore()
    {
        string text = base.GetNameCore();
        if (text == string.Empty)
        {
            IntPtr hwnd = base.Hwnd;
            if (hwnd != IntPtr.Zero)
            {
                try
                {
                    StringBuilder stringBuilder = new StringBuilder(512);
Throws  ======>     MS.Win32.UnsafeNativeMethods.GetWindowText(new HandleRef(null, hwnd), stringBuilder, stringBuilder.Capacity);
                    text = stringBuilder.ToString();
                }
                catch (Win32Exception)
                {
                }
                if (text == null)
                {
                    text = string.Empty;
                }
            }
        }
        return text;
    }

设置 AutomationProperties.NameProperty 可确保 base.GetNameCore() 返回有效字符串,从而导致跳过有问题的代码。

【讨论】:

  • 谢谢罗兰。我真的不喜欢这个解决方案,但它解决了这个问题。你找到更流畅的解决方案了吗?
  • @Bjqn 您使用的是 .NET Framework 还是 .NET Core?似乎 Core 仍然存在这个问题,但也许值得将其作为一个错误提交,以便在 6.0 之前修复它。
  • @SörenKuklau 我正在使用 .Net Framework 4.7.2
猜你喜欢
  • 2013-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-04
  • 2011-03-24
  • 1970-01-01
  • 2012-05-31
相关资源
最近更新 更多