代码之家  ›  专栏  ›  技术社区  ›  Daniel Rose

强制初始化HwndHost

  •  5
  • Daniel Rose  · 技术社区  · 14 年前

    在我的WPF应用程序中,我使用hwndhost托管win32内容。但是,创建hwndhost不会创建本机窗口。相反,这是在重写的 BuildWindowCore() 方法,稍后由WPF调用。

    我托管的内容需要本机窗口的窗口句柄来进行初始化。不幸的是,我无法强制创建窗口(即让wpf调用buildWindowCore),所以我有第二个线程来轮询hwndhost,直到它被初始化。

    在.NET 4.0/WPF 4.0中,一种新方法 WindowInteropHelper.EnsureHandle() 加入。我本来希望这样可以解决这个问题,但它只适用于一个窗口,而不适用于hwndhost(它不是从窗口派生的)。你有什么建议我可以做什么?

    编辑:

    我忘记为可能的解决方案添加更多约束:

    1. hwndhost被放置在一个控件中,该控件可以是应用程序主窗口的子窗口,也可以放置在新窗口中(通过第三方停靠管理器)。这意味着在创建窗口的过程中,我不确定父窗口(以及它的Hwnd)是什么。
    2. 虽然本机代码在初始化过程中需要hwnd,但只有当用户请求显示时(即最初不可见),才会显示该窗口。如果可能,应避免显示窗口,只需立即再次隐藏。
    4 回复  |  直到 11 年前
        1
  •  3
  •   Daniel Rose    13 年前

    似乎没有完美的解决方案。与提问时间相比,我稍微改变了一下方法:

    在我的hwndhost派生类的构造函数中,我有(可能的)父hwnd作为参数之一。然后我使用本机创建本机窗口 CreateWindow() 方法,使用给定的父Hwnd。我将创建的hwnd存储在一个单独的属性中,在任何地方都使用它,而不是hwndhost的handle属性。这样,我不需要显示窗口(这解决了约束2)。

    在重写的 BuildWindowCore() 方法,将给定的父hwnd与构造函数中给定的父hwnd进行比较。如果它们不同,我将使用本机 SetParent() 方法(这解决了约束1)。请注意,这依赖于没有人存储父hwnd!

    在代码中,相关部分(省略检查):

    public class Win32Window : HwndHost
    {
        public Win32Window(IntPtr parentHwnd)
        {
            this.ParentHwnd = parentHwnd;
            this.Win32Handle = NativeMethods.CreateWindowEx( /* parameters omitted*/ );
        }
    
        public IntPtr Win32Handle { get; private set; }
        private IntPtr ParentHwnd { get; set; }
    
        protected override HandleRef BuildWindowCore(HandleRef hwndParent)
        {
            if (hwndParent.Handle != this.ParentHwnd)
            {
                NativeMethods.SetParent(this.Win32Handle, hwndParent.Handle);
            }
    
            return new HandleRef(this, this.Win32Handle);
        }
    }
    
        2
  •  1
  •   17 of 26    14 年前

    我有一个类似的情况,我通过执行以下操作解决了它:

    1)创建一个hwndhost派生类,该类将rect作为构造函数参数(稍后在buildWindowCore中使用):

    public class MyHwndHost : HwndHost
    {
        public MyHwndHost(Rect boundingBox)
        {
            BoundingBox = boundingBox;
        } 
    }
    

    2)使用子边框元素创建WPF窗口:

    <Window Loaded="Window_Loaded">
        <Border Name="HostElement" />
    </Window>
    

    3)创建hwndhost实例并将其添加到窗口“加载处理程序”中的窗口中:

    void Window_Loaded(object sender, RoutedEventArgs e)
    {
        MyHwndHost host = new MyHwndHost(LayoutInformation.GetLayoutSlot(HostElement));
        HostElement.Child = host;
    }
    

    4)在Windows加载的处理程序中,通过P/Unjk或C++/CLI将HWND传递到本地类的初始化。我已经设置了我的本机类来使用该hwnd作为其父级,它创建自己的hwnd作为子级。

        3
  •  0
  •   Cechner    13 年前

    有点晚了,但是你打过电话吗 UpdateLayout() 在宿主控件上?对我有用

        4
  •  0
  •   Rich    11 年前

    我添加了活动 OnHandleCreated 对我 HwndHost -继承的类,其中包含句柄Intpr。此事件在内部调用 BuildWindowCore() .

    public class Win32WindowHost : HwndHost { ... }

    var host = new Win32WindowHost();
    host.OnHandleCreated += ( sender, e ) =>
    {
        var handle = e.Handle;
        // Do stuff.
    };
    

    奏效。

    推荐文章