如何将C# Form设为已有外部窗口的子窗口并嵌入WPF控件
实现方案建议
1. 把WinForm绑定为原生嵌入窗口的子窗口
你已经通过P/Invoke完成原生窗口嵌入外部应用的操作,接下来要让WinForm成为它的子窗口,核心调用SetParent API即可:
- 实例化自定义WinForm时,务必设置
FormBorderStyle = FormBorderStyle.None,去掉自带边框和标题栏,适配嵌入场景; - 拿到你创建的原生窗口HWND(你肯定已经持有这个句柄),调用
SetParent把Form的Handle挂到它下面; - 同步Form的尺寸到原生窗口,确保完全填充:
// hNativeEmbeddedWindow是你P/Invoke创建的原生窗口句柄 var childForm = new YourCustomForm(); childForm.FormBorderStyle = FormBorderStyle.None; childForm.Show(); // 必须先Show才能获取有效Handle SetParent(childForm.Handle, hNativeEmbeddedWindow); // 同步大小到原生窗口 var rect = new RECT(); GetWindowRect(hNativeEmbeddedWindow, out rect); childForm.Size = new Size(rect.Right - rect.Left, rect.Bottom - rect.Top); childForm.Location = new Point(0, 0); // 必要的P/Invoke声明 [DllImport("user32.dll")] private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); public struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
2. 在WinForm里嵌入WPF控件
C# 4.7.2自带WinForm与WPF的互操作支持,用ElementHost就能快速实现:
- 可以在WinForm设计器中拖入
ElementHost控件,也可以用代码创建; - 实例化你的WPF用户控件(比如
YourWpfUserControl),将其赋值给ElementHost.Child属性; - 设置
ElementHost的Dock为Fill,让WPF控件占满整个Form:
// 代码创建ElementHost和WPF控件 var elementHost = new ElementHost(); elementHost.Dock = DockStyle.Fill; var wpfControl = new YourWpfUserControl(); // 在这里配置WPF控件的属性,比如绑定数据、设置样式等 wpfControl.Background = Brushes.LightGray; wpfControl.TitleText = "嵌入的WPF控件"; elementHost.Child = wpfControl; childForm.Controls.Add(elementHost);
3. 关键注意点
- UI线程一致性:WinForm和WPF控件必须在同一个UI线程创建和操作,Windows UI控件不允许跨线程访问,如果你的原生窗口操作在非UI线程,一定要切换到UI线程再处理Form和WPF控件;
- 尺寸同步:原生窗口大小变化时,要同步更新WinForm和ElementHost的尺寸,可以监听原生窗口的
WM_SIZE消息,或者给WinForm添加Resize事件触发WPF控件的布局更新; - 资源清理:退出时要正确销毁Form、ElementHost和WPF控件,避免内存泄漏,比如在原生窗口销毁时调用
childForm.Close(); - 程序集引用:确保项目引用了
WindowsFormsIntegration、PresentationFramework、PresentationCore这几个WPF相关的程序集,否则会编译报错。
内容的提问来源于stack exchange,提问作者Tom Lee
相关产品推荐
相关产品推荐

