You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于在WinUI 3应用中嵌入现有WinForms应用的技术咨询

关于在WinUI 3应用中嵌入现有WinForms应用的技术咨询

嘿,刚好我之前研究过类似的需求,WinUI 3虽然没有WPF那种现成的WindowsFormsHost控件,但通过桌面端的互操作能力,完全可以实现把WinForms应用嵌入到TabView里、在标签页之间切换的效果!下面给你梳理下具体的实现思路和步骤:

前提准备

首先得确保你的WinUI 3项目是Desktop应用模型(也就是创建项目时选“WinUI 3 Desktop App”),只有桌面模型才能和Win32/WinForms进行底层互操作。另外要给项目安装必要的NuGet包:System.Windows.Forms,如果需要更方便调用Win32 API,还可以装PInvoke.User32(当然也可以自己声明Win32函数)。

核心实现思路

核心逻辑是把WinForms窗体作为子窗口嵌入到WinUI 3的TabViewItem容器中,通过Win32 API来绑定窗口父子关系,再同步两者的布局大小。具体步骤如下:

1. 创建并配置WinForms窗体

当你要新增一个TabView标签页时,先实例化你的WinForms应用主窗体(或者现有WinForms程序的入口窗体),记得把窗体边框去掉,避免和WinUI的TabView样式冲突:

var winFormsAppForm = new YourWinFormsMainForm();
winFormsAppForm.FormBorderStyle = FormBorderStyle.None; // 去掉自带边框
winFormsAppForm.Text = "嵌入的WinForms应用";

2. 构建WinUI的TabViewItem

给TabView添加新的标签页,用一个Grid作为标签页的内容容器(方便后续获取句柄和同步大小):

var newTab = new TabViewItem();
newTab.Header = "WinForms应用标签";
var contentContainer = new Grid();
newTab.Content = contentContainer;

// 添加到TabView并选中
yourTabViewControl.TabItems.Add(newTab);
yourTabViewControl.SelectedItem = newTab;

3. 绑定窗口父子关系(关键步骤)

通过Win32的SetParent API,把WinForms窗体的句柄设置为WinUI容器的句柄,这样WinForms窗体就会嵌入到TabViewItem里:

// 获取WinUI容器的HWND
IntPtr containerHwnd = WindowNative.GetWindowHandle(contentContainer);
// 获取WinForms窗体的HWND
IntPtr formHwnd = winFormsAppForm.Handle;

// 调用Win32 API设置父窗口
PInvoke.User32.SetParent(formHwnd, containerHwnd);

4. 同步布局大小

为了避免WinForms窗体和WinUI容器大小不一致,要监听容器的尺寸变化,同步更新WinForms窗体的大小:

contentContainer.SizeChanged += (s, e) =>
{
    if (winFormsAppForm != null && !winFormsAppForm.IsDisposed)
    {
        winFormsAppForm.Size = new System.Drawing.Size(
            (int)contentContainer.ActualWidth,
            (int)contentContainer.ActualHeight);
    }
};

5. 显示WinForms窗体

最后别忘了显示WinForms窗体,否则它不会出现在TabView里:

winFormsAppForm.Show();

重要注意事项

  • 线程模型:桌面WinUI 3默认是STA线程,和WinForms的线程模型兼容,不需要额外处理线程问题,但要避免跨线程操作UI。
  • 生命周期管理:当关闭TabViewItem时,一定要主动关闭WinForms窗体并释放资源,比如在TabView的TabCloseRequested事件里处理:
    private void YourTabView_TabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args)
    {
        var tabItem = args.Tab;
        var container = tabItem.Content as Grid;
        // 这里可以通过容器关联的WinForms窗体实例(可以提前存在Tag里)来关闭
        var winFormsForm = container.Tag as Form;
        winFormsForm?.Close();
        winFormsForm?.Dispose();
        sender.TabItems.Remove(tabItem);
    }
    
  • 模态窗口处理:如果你的WinForms应用有模态弹窗,默认会以WinForms窗体为父窗口,可能会跳出WinUI容器,这时候需要在弹窗显示前,把弹窗的父窗口也设置为WinUI容器的句柄。
  • 性能问题:如果嵌入多个WinForms窗体,要注意内存和性能消耗,及时释放不用的窗体资源。

备注:内容来源于stack exchange,提问作者Manuel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 10:18:13