赞
踩
unity3D界面不能够直接嵌入到WPF控件中,但是可以嵌入到WinForm控件中,所以我们需要在WPF中使用WinForm控件作为载体。需要引用上述dll,如下图所示:
然后在Xaml文件中引入命名空间即可使用WinForm控件,例如:
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
<WindowsFormsHost Grid.Row="1">
<wf:Panel/>
</WindowsFormsHost>
public class AppContainer { private System.Windows.Forms.Panel _hostPanel; private readonly ManualResetEvent _eventDone = new ManualResetEvent(false); private Process _process = null; internal IntPtr _embededWindowHandle; public AppContainer(System.Windows.Forms.Panel panel) { this._hostPanel = panel; this._hostPanel.Resize += _hostPanel_Resize; } private void _hostPanel_Resize(object sender, EventArgs e) { SetBounds(); } public void ActivateWindow() { if (_process == null) return; if (_process.MainWindowHandle == IntPtr.Zero) return; Win32Api.SendMessage(_process.MainWindowHandle, Win32Api.WM_ACTIVATE, Win32Api.WA_ACTIVE, IntPtr.Zero); } public void SetBounds() { SetBounds(_hostPanel.Width, _hostPanel.Height); } public void SetBounds(int width, int height) { if (_process == null) return; if (_process.MainWindowHandle == IntPtr.Zero) return; if (width <= 0 || height <= 0) return; Win32Api.MoveWindow(_process.MainWindowHandle, 0, 0, width, height, true); ActivateWindow();//激活 } public bool StartAndEmbedProcess(string processPath) { if (null != _process) return true; var isStartAndEmbedSuccess = false; _eventDone.Reset(); // Start the process ProcessStartInfo info = new ProcessStartInfo(processPath); info.WindowStyle = ProcessWindowStyle.Maximized;//默认最大化,不弹出界面。 info.Arguments = $"-popupwindow";//Unity的命令行参数 _process = Process.Start(info); if (_process == null) { return false; } // Wait for process to be created and enter idle condition _process.WaitForInputIdle(); // Get the main handle var thread = new Thread(() => { while (true) { if (_process.MainWindowHandle != (IntPtr)0) { _eventDone.Set(); break; } Thread.Sleep(10); } }); thread.Start(); //嵌入进程 if (_eventDone.WaitOne(10000)) { isStartAndEmbedSuccess = EmbedApp(_process); if (!isStartAndEmbedSuccess) { CloseApp(_process); } } return isStartAndEmbedSuccess; } public bool EmbedExistProcess(Process process) { _process = process; return EmbedApp(process); } /// <summary> /// 将外进程嵌入到当前程序 /// </summary> /// <param name="process"></param> private bool EmbedApp(Process process) { //是否嵌入成功标志,用作返回值 var isEmbedSuccess = false; //外进程句柄 var processHwnd = process.MainWindowHandle; //容器句柄 var panelHwnd = _hostPanel.Handle; if (processHwnd != (IntPtr)0 && panelHwnd != (IntPtr)0) { //把本窗口句柄与目标窗口句柄关联起来 var setTime = 0; while (!isEmbedSuccess && setTime < 50) { // Put it into this form isEmbedSuccess = Win32Api.SetParent(processHwnd, panelHwnd) != 0; Thread.Sleep(10); setTime++; } // Remove border and whatnot //Win32Api.SetWindowLong(processHwnd, Win32Api.GWL_STYLE, Win32Api.WS_CHILDWINDOW | Win32Api.WS_CLIPSIBLINGS | Win32Api.WS_CLIPCHILDREN | Win32Api.WS_VISIBLE); SetBounds(); Move the window to overlay it on this window //Win32Api.MoveWindow(_process.MainWindowHandle, 0, 0, (int)ActualWidth, (int)ActualHeight, true); } if (isEmbedSuccess) { _embededWindowHandle = _process.MainWindowHandle; } return isEmbedSuccess; } /// <summary> /// 关闭进程 /// </summary> /// <param name="process"></param> private void CloseApp(Process process) { if (process != null && !process.HasExited) { process.Kill(); } } public void CloseProcess() { CloseApp(_process); _process = null; } }
这是一个嵌入的实例类,构造函数会把WinForm控件以参数的形式传入,然后此控件需要订阅Resize事件,该事件处理器进行了unity3D窗体的重新激活。
在进程启动的时候使用了命令行参数info.Arguments = $"-popupwindow";//Unity的命令行参数。
依然使用的Win32Api设置为父窗体, Win32Api.SetParent(processHwnd, panelHwnd)。
实例代码如下:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Button Margin="3" Content="Embed" Click="Button_Click" HorizontalAlignment="Center"/>
</Grid>
<WindowsFormsHost Grid.Row="1">
<wf:Panel x:Name="host"/>
</WindowsFormsHost>
</Grid>
private void Button_Click(object sender, RoutedEventArgs e)
{
AppContainer container = new AppContainer(this.host);
container.StartAndEmbedProcess(@"Child.exe");
}
鼠标和键盘均可正常响应。
最后、如对你有帮助,求关注、求一键三连,感谢
目前很多项目使用的.NetCore,然后发现用不了上述说的dll。那么因为需要在项目文件中添加如下信息:
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<AssemblyName>SIFP.Core</AssemblyName>
</PropertyGroup>
将WinForm嵌入到WPF中后,WinForm控件只能覆盖在WPF控件上,不知道有没有大佬知道怎么使WPF控件覆盖在WinForm上???
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。