如何将单个Unity .exe进程嵌入多个WPF Page实现不同场景切换显示
实现方案
完全可以实现同一运行态Unity进程多页面复用、后台保活的需求,不需要每次导航重启Unity进程,具体实现思路如下:
1. 核心逻辑改造点
不要将Unity嵌入逻辑绑定到单个Page,而是把Unity进程、承载用的WinForms Panel都做成全局单例,仅在程序启动时初始化一次,页面导航时仅做宿主容器的挂载/卸载操作,不触碰Unity进程本身。
2. 具体实现步骤
第一步:构建全局Unity管理单例
封装静态管理类,统一处理Unity进程启动、承载Panel的缓存、挂载卸载逻辑,核心代码参考如下:
public static class UnityHostManager { // 全局唯一的Unity承载WinForms Panel public static System.Windows.Forms.Panel UnityPanel { get; private set; } // 全局唯一的Unity进程实例 public static Process UnityProcess { get; private set; } // 后台缓存用的隐藏宿主,无页面展示时存储UnityPanel private static WindowsFormsHost _hiddenCacheHost = new WindowsFormsHost { Visibility = Visibility.Hidden }; // 程序启动时仅调用一次,初始化Unity进程和嵌入逻辑 public static void InitUnity() { if (UnityProcess != null) return; UnityPanel = new System.Windows.Forms.Panel(); // 此处复用你原有启动Unity进程、获取窗口句柄、嵌入到Panel的逻辑 // ......原有嵌入代码...... // 初始化后先放入隐藏缓存宿主 _hiddenCacheHost.Child = UnityPanel; } // 将Unity Panel挂载到当前页面的WindowsFormsHost public static void AttachToPageHost(WindowsFormsHost currentPageHost) { if (UnityPanel == null) InitUnity(); // 先从原有父容器卸载 var oldHost = UnityPanel.Parent as WindowsFormsHost; if (oldHost != null) oldHost.Child = null; // 挂载到当前页面的宿主 currentPageHost.Child = UnityPanel; // 可选:发送重绘消息避免Unity窗口错位黑屏 } // 将Unity Panel卸载回后台缓存 public static void DetachToCache() { if (UnityPanel == null) return; var currentHost = UnityPanel.Parent as WindowsFormsHost; if (currentHost != null) currentHost.Child = null; _hiddenCacheHost.Child = UnityPanel; } }可以在
App.xaml.cs的OnStartup方法中调用UnityHostManager.InitUnity(),程序启动时就初始化Unity进程,也可以懒加载在第一次进入带Unity的页面时初始化。第二步:改造带Unity展示的页面逻辑
每个需要展示Unity的Page的XAML还是保留原有结构,只需要给WindowsFormsHost命名即可:
<WindowsFormsHost x:Name="UnityHostContainer"/>在页面的
Loaded和Unloaded事件中处理挂载、卸载逻辑,同时调用你已有的TCP接口切换对应场景:private void Page_Loaded(object sender, RoutedEventArgs e) { UnityHostManager.AttachToPageHost(UnityHostContainer); // 调用TCP接口,通知Unity切换到当前页面对应的场景,比如Page1发切Scene1的指令 } private void Page_Unloaded(object sender, RoutedEventArgs e) { UnityHostManager.DetachToCache(); }第三步:无Unity页面的后台保活处理
导航到不需要展示Unity的普通页面时,不需要做任何额外操作,Unity进程会一直运行在后台,承载Panel放在隐藏的缓存宿主中不会被销毁,TCP连接也可以保持,下次进入带Unity的页面时直接挂载即可,不需要重新加载。
3. 可选优化方案
你提到的UserControl方案完全可行,可以把挂载卸载逻辑封装到一个UnityHostUserControl中,每个需要展示Unity的Page直接放置这个UserControl即可,不需要每个页面重复写Loaded/Unloaded事件逻辑,复用性更高。
注意事项
- 挂载完成后可以给Unity窗口发送重绘消息,或者调用
SetWindowPos刷新位置,避免出现黑屏、错位问题 - WPF程序退出时要主动杀掉Unity进程,避免留下孤儿后台进程
- 多页面切换场景时可以加个过渡动画,掩盖Unity场景加载的间隙,提升体验
内容的提问来源于stack exchange,提问作者NiklasMoller

