使用Winform控件承载外部程序
- 在WPF中使用Winfom控件
- 添加winform相关的程序集
- 在XAML头中加入对这两个程序集命名空间的引用
- 使用Winform控件
- 效果:
- 问题
- 在Winfom控件中嵌入exe程序
- 准备Winfrom控件
- 更换父窗体的句柄
- 完整实现代码:
- 实现效果:
- 问题和后续更新
在WPF中使用Winfom控件
首先要解决在WPF中如何使用Winfom控件的问题,官方对此有支持的方式。
添加winform相关的程序集
在引用管理器中添加winfrom相关的程序集System.Windows.Forms
和WindowsFormsIntegration
。
在XAML头中加入对这两个程序集命名空间的引用
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:wfi ="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
使用Winform控件
然后使用winform的控件,得在外面套一层WindowsFormsHost(好像添加了WindowsFormsIntegration,不使用wfi:也能使用)
<wfi:WindowsFormsHost Margin="0,0,400,73"><wf:TextBox />
</wfi:WindowsFormsHost>
效果:
这样就可以在WPF中使用Winform控件,但是不推荐,除非特殊情况。
问题
这种方式存在的问题:
-
WindowsFormsHost依旧是显示在最前,暂时没找到解决方法,尽量从设计上避免
-
后台无法获取到WindowsFormsHost内部控件的名称,只能通过
WindowsFormsHost
获取内部控件的句柄。
在Winfom控件中嵌入exe程序
准备Winfrom控件
WindowsFormsHost
中控件换成Panel
<wfi:WindowsFormsHost Name="WFHost" Margin="0,0,400,73"><wf:Panel />
</wfi:WindowsFormsHost>
更换父窗体的句柄
将获取主窗体句柄换成获取Panel句柄,然后设置窗体大小跟WindowsFormsHost
控件一样
//当前窗体/容器(主程序)句柄IntPtr hwnd = WFHost.Child.Handle;//设置窗体位置和大小MoveWindow(appWin, 0, 0, (int)WFHost.ActualWidth, (int)WFHost.ActualHeight, true);
完整实现代码:
上述功能完整实现的代码如下
可以更新到上一篇的MainWindow的代码中去。
var exeName = "C:\\WINDOWS\\system32\\mspaint";//使用Process运行程序Process p = new Process();p.StartInfo.FileName = exeName;p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;p.Start();//获取窗体句柄while (p.MainWindowHandle.ToInt32() == 0){System.Threading.Thread.Sleep(100);}IntPtr appWin = p.MainWindowHandle;//子窗体(外部程序)句柄//当前窗体/容器(主程序)句柄IntPtr hwnd = WFHost.Child.Handle;//设置父窗体(实现窗体嵌入)SetParent(appWin, hwnd);//设置窗体样式var style = GetWindowLong(appWin, GWL_STYLE);SetWindowLong(appWin, GWL_STYLE, style & ~WS_CAPTION & ~WS_THICKFRAME);//设置窗体位置和大小MoveWindow(appWin, 0, 0, (int)WFHost.ActualWidth, (int)WFHost.ActualHeight, true);
实现效果:
搞个Grid分多行和列,进行拖动操作,可以看到子窗体显示区域限制在WindowsFormsHost 内部了,拖动变化子窗体不会超出显示区域。
问题和后续更新
子窗体实现大小还是固定的,没有随着控件变化实时调整,需要窗体或者控件调整大小重绘时,使用MoveWindow
刷新,以达到子窗体尺寸跟随控件尺寸的大小,实现更好的嵌入。