从最内层WPF用户控件获取父窗口的问题求助
问题场景
我有一套嵌套层级的控件结构:
- 内层WPF用户控件
UCInner(包含WPF Popup) UCInner被嵌套在另一个WPF用户控件UCOuter中UCOuter通过ElementHost.Child嵌入到WinForms环境- 最终整体作为Outlook VSTO自定义任务窗格运行
尝试从UCInner获取父窗口时,以下代码均返回null或抛出异常:
Window w = Window.GetWindow(myPopup); Window w = Window.GetWindow(UCInner);
后续通过Outlook API成功获取到窗口句柄,但使用HwndSource.FromHwnd(handle)时返回null,无法转换为WPFWindow对象:
dynamic activeWindow = Globals.ThisAddIn.Application.ActiveWindow(); Microsoft.VisualStudio.OLE.Interop.IOleWindow win = activeWindow as Microsoft.VisualStudio.OLE.Interop.IOleWindow; IntPtr handle; win.GetWindow(out handle); // 此步骤返回null System.Windows.Interop.HwndSource hwndSource = System.Windows.Interop.HwndSource.FromHwnd(handle); Window w = hwndSource.RootVisual as Window;
解决方案
方法1:从WPF控件向上遍历找到ElementHost,获取WinForms宿主窗口
你的WPF控件嵌入在WinForms的ElementHost中,没有对应的WPF顶级Window,可以先找到ElementHost,再获取其所在的WinForms窗口:
using System.Windows.Media; using System.Windows.Forms.Integration; // 从UCInner向上遍历Visual树,找到ElementHost DependencyObject currentElement = UCInner; while (currentElement != null && !(currentElement is ElementHost)) { currentElement = VisualTreeHelper.GetParent(currentElement); } if (currentElement is ElementHost host) { // 获取WinForms宿主窗口 System.Windows.Forms.Form parentForm = host.FindForm(); if (parentForm != null) { IntPtr formHandle = parentForm.Handle; // 示例:将WPF窗口的Owner设置为该WinForms窗口句柄 WindowInteropHelper helper = new WindowInteropHelper(new Window()); helper.Owner = formHandle; // 或处理Popup的层级问题 myPopup.PlacementTarget = UCInner; myPopup.IsOpen = true; } }
方法2:直接使用Outlook窗口句柄关联WPF控件
不需要将Outlook窗口句柄转换为WPFWindow对象,而是用WindowInteropHelper将WPF窗口与原生句柄绑定,实现父子窗口层级:
// 假设已经通过Outlook API拿到窗口句柄handle // 为新WPF窗口设置Owner Window targetWindow = new Window(); WindowInteropHelper helper = new WindowInteropHelper(targetWindow); helper.Owner = handle; targetWindow.ShowDialog(); // 对于Popup,直接设置PlacementTarget确保层级正确 myPopup.PlacementTarget = UCInner; myPopup.Placement = System.Windows.Controls.Primitives.PlacementMode.Relative; myPopup.IsOpen = true;
无效原因说明
Window.GetWindow仅能识别WPF自身的顶级Window,你的WPF控件嵌入在WinForms环境中,没有对应的WPF顶级窗口,因此返回null。HwndSource.FromHwnd(handle)返回null是因为该句柄属于Outlook原生窗口,并非WPF通过HwndSource创建的窗口,WPF无法将其识别为自身的窗口源。
内容的提问来源于stack exchange,提问作者Willy
相关产品推荐
相关产品推荐

