WinForms/WPF/WinUI 的选型方法 - 实务判断表

· 更新日期: · · WinForms, WPF, WinUI, C#, Windows 开发, UI 设计

更新记录(2 条,最后更新 2026年09月03日)

本文的修改记录。已保存的更新前版本,可通过带有 DOI 的永久链接阅读。

本文此前是日文原文的节译,缺少大量章节、表格、Mermaid 图、图题、脚注与 FAQ。现已改写为日文原文的完整译文,技术主张与日文版一致,并补上了此前缺失的图与表,同时统一了全篇的术语译法。 查看更新前的版本 (DOI: 10.5281/zenodo.22276875)
补充了日文原文中已有的咨询引导(consultation_services)。正文内容没有改动。 查看更新前的版本 (DOI: 10.5281/zenodo.21615505)
首次发布
引用本文(DOI: 10.5281/zenodo.21615504)

本文保存于 Zenodo。以下同时提供始终指向最新版本的 DOI,以及固定于您正在阅读版本的 DOI。

小村 豪(2026)。《WinForms/WPF/WinUI 的选型方法 - 实务判断表》。小村软件有限公司。https://doi.org/10.5281/zenodo.21615504 https://comcomponent.com/zh-CN/blog/2026/03/18/001-winforms-wpf-winui-decision-table/

DOI(最新版本)
10.5281/zenodo.21615504
DOI(此版本)
10.5281/zenodo.22282027

目标读者:用 C# / .NET 开发 Windows 桌面应用的开发者,以及负责决定技术选型的人。 前提:使用现行的 .NET(不是 .NET Framework),目标平台仅限 Windows。 阅读方式:只想看结论就读第 1 章和第 3 章,想决定现有应用的延续维护方针就读第 7 章,想要最后的决定性依据就从第 8 章开始读。

用 C# / .NET 开发 Windows 桌面应用时, 每次都会默默让人纠结的,就是 WinForms、WPF、WinUI 到底该选哪一个。

这里危险的是,

  • 因为最新所以选 WinUI
  • 因为最熟悉所以选 WinForms
  • 因为感觉居中所以选 WPF

这类模糊的选法。

模糊选法的危险因为最新所以选WinUI、因为最熟悉所以选WinForms、因为感觉居中所以选WPF这类模糊的选法很危险,实务中要用更明确的维度来看的图。因为新所以选WinUI模糊的选法因为熟悉所以选WinForms因为居中所以选WPF实务中用明确的维度来看

图1:不用“新、熟悉、居中”来选,而是用明确的维度来选。

在实务中,该看的维度更明确一些。

  • 是全新开发,还是现有资产的延伸
  • 界面是以录入表单为主,还是需要表现力
  • Windows 风格的现代 UI 本身是不是产品价值
  • 发布、更新、企业内部运维怎么处理
  • 是以 Windows Forms Designer 为中心的开发方式,还是以 XAML/MVVM 为中心的开发方式

本文把这些整理成一张判断表。 另外,本文所说的 WinUI 主要指 WinUI 3 + Windows App SDK。12

还有,这 3 个框架全都是 Windows 专属的。 如果 macOS / Linux 也在视野之内,那问题的设定本身就不一样了。341

三者都是 Windows 专属WinForms、WPF、WinUI都是Windows专属的,如果macOS或Linux也在视野之内,问题的设定本身就不一样的图。WinForms全都是 Windows 专属WPFWinUImacOS / Linux也在视野内就是另一个问题设定

图2:三者都是 Windows 专属,要跨平台就是另一个问题设定。

1. 先说结论(一句话)

先给一个相当粗糙、但在实务中好用的说法,大致是这样。

  • 如果现有 WinForms 应用规模大,先以继续用 WinForms 为基本方向
  • 如果现有 WPF 应用规模大,先以继续用 WPF 为基本方向
  • 全新的小到中型企业内部工具,如果以标准控件为主、以录入界面为主,而且想快速做出来,WinForms 现在依然相当强35
  • 全新的中到大型业务应用,如果界面数量多,想踏实用好数据绑定、样式、模板、命令、MVVM,WPF 往往是最稳妥的467
  • 全新的 Windows 专属产品,如果现代 Windows UI、Fluent、最新 Windows 体验直接关系到产品价值,WinUI 很有优势12
  • 如果只是想用最新的 Windows API,那么并不一定要用 WinUI。WPF / WinForms 也可以引入 Windows App SDK 的功能28910
  • 以“以后慢慢把 WinUI 插进去就行”为前提来选型,是有点危险的。分阶段迁移这件事,比想象中更麻烦1011

概括起来,大致就是这么几条。

  1. 存量资产规模大,就先保住那条技术路线
  2. 全新项目要快速做标准表单,就选 WinForms
  3. 全新项目要做长期成长的 Windows 业务应用,就选 WPF
  4. 全新项目里现代 Windows UI 本身就是需求,就选 WinUI
  5. 只是想用 Windows App SDK,就不要一上来全部换成 WinUI

框架选型既是 UI 技术的选型,同时也是 发布、运维、学习成本、迁移成本的选型。 如果只用“新 / 旧”来决定,代价会在后续的发布设计和维护成本上反弹回来。

先说结论的决定方式存量资产规模大就先保住那条技术路线,全新项目要快速做标准表单就选WinForms,要做长期成长的Windows业务应用就选WPF,现代Windows UI本身是需求就选WinUI的决定方式的图。是否,全新项目是否否是存量资产是否规模大先保住那条技术路线是否以标准表单为主WinForms现代UI本身是否是需求WPF,长期成长的业务应用WinUI只为用SDK就不要全面换成WinUI

图3:按存量资产、界面性质、现代 UI 需求的顺序看下来,结论大致就定了。

图中实线表示始终成立的关系,虚线表示带条件的关系(成立条件写在详情页各关系的说明中)。关系的完整列表(共 24 条,附依据与确信度)以及主要概念的定义,汇总在知识地图详情页(日文)。数据:JSON-LD / Turtle

2. 本文所说的 3 种技术

先把用语统一一下。后面一直会出现的缩写,在这里先展开。

术语 全称 大致来说
XAML eXtensible Application Markup Language 用来声明式描述界面结构的、基于 XML 的标记语言。WPF 和 WinUI 都使用它
Designer Windows Forms Designer 在 Visual Studio 上拖动控件搭建界面的功能。生成结果会以 *.Designer.cs 这样的代码留下来
Data Binding 数据绑定 把界面的属性和数据侧的属性关联起来,一方发生变化时另一方随之跟进的机制
MVVM Model-View-ViewModel 把界面(View)、界面用的状态和命令(ViewModel)、业务逻辑和数据(Model)分开的设计模式。View 和 ViewModel 之间用 Data Binding 连接
Fluent Fluent Design System 规定了 Windows 11 外观和操作感受的 Microsoft 设计体系。WinUI 以它为前提
Windows App SDK — 包含 WinUI 在内的、面向当下 Windows 的开发库集合。除 UI 之外还有别的功能,也可以加到 WPF / WinForms / Win32 的现有应用里
XAML Islands — 只在现有 WPF / WinForms / Win32 应用的一部分中嵌入新的 XAML 控件的机制。详见 5.3.3
MSIX — Windows 的应用包格式。安装、更新、卸载都可以交给操作系统侧的机制处理
package identity 包标识 Windows 能识别出某个进程属于哪个应用包的状态。通知、关联等一部分 Windows 功能,没有它就用不了
技术 大致来说 强项
WinForms 用 Visual Studio 的 Designer 容易快速搭出表单的、Windows 上传统的 .NET 桌面 UI 快速搭建界面、标准控件、复用存量资产
WPF 用 XAML、数据绑定、样式、模板、命令,容易做出有表现力 UI 的 Windows 专用 UI 中到大型业务应用、MVVM、界面容易梳理
WinUI Windows App SDK 之上的现代 Windows 原生 UI Fluent、最新 Windows 体验、高 DPI、现代产品 UI

WinForms 在 Microsoft Learn 上也被描述为具备控件、图形、数据绑定、用户输入能力,容易用 Visual Studio 的拖放式 Designer 来做应用的框架。3

WPF 是包含与分辨率无关的矢量绘图、XAML、数据绑定、样式 / 模板、2D / 3D、动画在内、表现力很强的 UI 框架。4

WinUI 是 Windows App SDK 的一部分,是以高 DPI、现代输入方式、流畅动画、Fluent 系体验为前提的、面向当下 Windows 的 UI 框架。12 另外,data binding / MVVM 的引导路径它也正常具备。12

这里重要的是,Windows App SDK 和 WinUI 并不是同一个东西。 WinUI 是 Windows App SDK 的 UI 框架部分,但 Windows App SDK 本身也可以加到 WPF / WinForms / Win32 的现有应用里。210

所以,

  • 使用 WinUI
  • 使用 Windows App SDK 的功能

看起来相似,其实是两个不同的判断。 如果这两点混在一起讨论,“要不要迁移 UI”和“要不要增加功能”就会被当成同一件事,结论很难收敛。

Windows App SDK和WinUI不是一回事WinUI是Windows App SDK的UI框架部分,而Windows App SDK本身也可以加到WPF、WinForms、Win32的现有应用里,因此使用WinUI的判断和使用SDK功能的判断是不同的图。Windows App SDKWinUI,它的UI框架部分也可以加到 WPF / WinForms / Win32“使用WinUI”的判断“使用SDK功能”的判断看似相似其实是不同的判断

图4:“使用 WinUI”和“使用 Windows App SDK 的功能”是两个不同的判断。

3. 一页看懂的判断表

先放上实务中最好用的一张表。

情况 优先选 理由
现有 WinForms 应用的改造、延续维护、更新到现行 .NET 继续用 WinForms 容易复用现有界面、Designer 资产、控件资产
现有 WPF 应用的改造、延续维护、更新到现行 .NET 继续用 WPF 容易原样复用 XAML、Binding、MVVM、界面结构
全新项目、企业内部工具、设置界面、管理界面、以录入表单为主 WinForms 以标准控件为主的话上手快
全新项目、界面数量多、状态复杂、想用样式 / 模板 / MVVM WPF 容易做界面职责分离和 UI 梳理
全新项目、Windows 风格的现代 UI 本身就是需求 WinUI 容易贴近 Fluent 和最新的 Windows 体验
保持现有 WPF / WinForms 不变,想用 Toast / Windowing / App Lifecycle 等功能 现行框架 + Windows App SDK 为了最新的 Windows 功能,往往并不需要整体迁移 UI
对 COM / ActiveX / 老旧第三方控件的依赖较重 偏向现有框架 比起 UI,依赖关系的迁移成本更大
强烈受发布、更新、企业内部运维的约束 优先考虑 WPF / WinForms,选 WinUI 就要尽早确认发布设计 WinUI 需要尽早审视 Windows App SDK / 打包相关的前提问题
将来想做跨平台 把这 3 个之外的方案也纳入重新考虑 这 3 个框架全都是 Windows 专属

光靠这张表大体就够了,但还剩下两个容易纠结的点。

  1. 全新的 Windows 业务应用,该偏向 WinForms 还是 WPF
  2. 已经有现有 WPF / WinForms,还该不该转向 WinUI

这两点,对照后面按维度划分的对比表来考虑就容易判断了。

判断表之后仍留下的两个纠结只靠一页判断表,还会剩下全新Windows业务应用该偏向WinForms还是WPF,以及已经有现有WPF或WinForms还该不该转向WinUI这两点,需要用后面的对比表来考虑的图。一页判断表全新业务应用是WinForms还是WPF已经有存量还要不要转向WinUI用按维度划分的对比表来考虑

图5:判断表之后剩下的两个纠结,用按维度划分的对比表来考虑。

4. 按维度划分的对比表

这里不是官方的优劣评比,而是相当偏实务的对比。

维度 WinForms WPF WinUI
快速做小型录入表单 ◎ ○ ○
以标准控件为主的企业内部工具 ◎ ○ △~○
与数据绑定 / MVVM 的契合度 △ ◎ ○~◎
样式 / 模板 / 界面的表现力 △ ◎ ◎
与现有 Windows 桌面资产的亲和性 ◎ ○ △
现代 Windows 风格 △ ○ ◎
现有界面的延续维护、分阶段改造 ◎ ◎ △
只想增加 Windows App SDK 的功能 ○ ○ ◎
发布 / 更新 / 运维设计的轻量程度 ○ ○ △~○
打造“全新且能长期成长的 Windows 专属产品 UI” △ ○ ◎

看表的窍门不是找谁最强,而是找谁的摩擦最少。

比如,

  • 企业内部的设置工具
  • 设备设置界面
  • 列表、明细、搜索、设置、按钮
  • 比起外观,更看重运维的稳定和改造速度

这类场景下,WinForms 现在依然足够合理。

反过来,

  • 界面数量多
  • 显示状态切换频繁
  • 想把 View 和逻辑分开
  • 想让数据的变化自然地反映到 UI 上
  • 想用样式 / 模板统一管控 UI

这类场景下,WPF 很好用。67

而且,

  • 想以 Windows 11 风格的外观为前提
  • 想踏实用好 Fluent
  • 想以高 DPI、触控、现代窗口 API 为前提
  • 是全新项目,而且作为 Windows 专属产品,UI 给人的印象也很重要

这类场景下,选 WinUI 就很自然。12

按摩擦少来选窍门不是找谁最强而是找谁的摩擦最少,以标准控件为主的企业内部工具适合WinForms,界面数量多且想用MVVM的项目适合WPF,以Fluent和最新Windows体验为前提的项目适合WinUI的图。谁的摩擦最少企业内部工具、以标准控件为主界面数量多且想用MVVM以Fluent、最新Windows体验为前提WinFormsWPFWinUI

图6:不是按“谁最强”,而是按“谁的摩擦最少”来区分使用这 3 者。

4.1 用最小的代码看清“表现力的差别”

上表里的“与数据绑定 / MVVM 的契合度”,光靠文字很难把握。下面用最小的代码,把同一个界面用 WinForms 和 WPF 分别写出来会有什么不同并排放一下。

要做的只是“一个文本框加一个保存按钮”的界面。

WinForms:Designer 生成 *.Designer.cs,然后在事件处理器里从界面取出值。

// MainForm.Designer.cs —— Designer 生成的一侧,不是手写的地方
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Button saveButton;

private void InitializeComponent()
{
    this.nameTextBox = new System.Windows.Forms.TextBox();
    this.saveButton = new System.Windows.Forms.Button();
    this.SuspendLayout();

    this.nameTextBox.Location = new System.Drawing.Point(12, 12);
    this.nameTextBox.Size = new System.Drawing.Size(200, 23);

    this.saveButton.Location = new System.Drawing.Point(218, 12);
    this.saveButton.Size = new System.Drawing.Size(75, 23);
    this.saveButton.Text = "保存";
    this.saveButton.Click += new System.EventHandler(this.SaveButton_Click);

    this.Controls.Add(this.nameTextBox);
    this.Controls.Add(this.saveButton);
    this.ResumeLayout(false);
}
// MainForm.cs —— 这一侧才是手写的地方
public partial class MainForm : Form
{
    private readonly EditorService _service;

    public MainForm(EditorService service)
    {
        _service = service;
        InitializeComponent();
    }

    private void SaveButton_Click(object sender, EventArgs e)
    {
        // 直接从界面的控件里取出值再传过去
        _service.Save(this.nameTextBox.Text);
    }
}

WPF:XAML 里只写“和什么连起来”,值的进出交给 Binding。

<!-- MainWindow.xaml -->
<Window x:Class="MyApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="编辑" Width="360" Height="120">
    <StackPanel Orientation="Horizontal" Margin="12">
        <TextBox Width="200"
                 Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
        <Button Width="75" Margin="6,0,0,0" Content="保存"
                Command="{Binding SaveCommand}" />
    </StackPanel>
</Window>
// MainWindow.xaml.cs —— 忘了传 DataContext 的话,Binding 什么都不会发生
public partial class MainWindow : Window
{
    public MainWindow(EditorService service)
    {
        InitializeComponent();
        this.DataContext = new MainViewModel(service);
    }
}
// MainViewModel.cs —— 不知道界面存在的一侧。单元测试也可以写在这里
public sealed class MainViewModel : INotifyPropertyChanged
{
    private readonly EditorService _service;
    private string _name = string.Empty;

    public MainViewModel(EditorService service)
    {
        _service = service;
        SaveCommand = new RelayCommand(() => _service.Save(Name));
    }

    public string Name
    {
        get => _name;
        set
        {
            if (_name == value) return;
            _name = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
        }
    }

    public ICommand SaveCommand { get; }

    public event PropertyChangedEventHandler PropertyChanged;
}

RelayCommand 是实现了 ICommand 的一个小类,CommunityToolkit.Mvvm 之类的库里就有,自己写也就 20 行左右。

只看行数的话,WPF 这边更多。差别是从这里开始体现的。

  WinForms WPF
从界面取值的地方 在事件处理器里直接读 nameTextBox.Text Name 属性,不碰 View
对保存处理做单元测试 需要把 Form 立起来 直接 new 出 MainViewModel 来调用
把同一个输入框放到另一个界面上 重新摆一遍控件,处理器也要重写 给同一个 ViewModel 配另一个 View
统一所有界面的外观 逐个调整各控件的属性 把 Style / Template 放在一处

界面只有 3 个时 WinForms 更快,到了 30 个时 WPF 更轻松,这就是这个差别在实务上的含义。

值的流向的差别WinForms中事件处理器直接从界面控件取出值再传给服务,而WPF中Binding把View和ViewModel连接起来,由不知道界面存在的ViewModel调用服务,两者值的流向不同的图。WPFWinFormsBindingView的XAMLViewModel调用服务事件处理器View的控件直接调用服务3个界面时更快30个界面也轻松

图7:WinForms 直接从界面取值,WPF 则由 Binding 转交给 ViewModel 承担。

5. 各自适合什么样的项目

5.1 WinForms

WinForms 常常被莫名轻视,但 在快速做出以标准控件为主的业务界面这一点上,它现在依然不容小觑。35

特别适合的,例如下面这类项目。

  • 企业内部用的设置工具
  • 设备、测量仪器、监控工具的设置界面
  • 管理界面、搜索界面、列表 + 明细
  • 现有 WinForms 资产规模大的项目
  • 以 Windows Forms Designer 为中心的开发方式很强势的团队

WinForms 的强项在于,不用引入什么复杂的思想,就能相当快地做出接近成品的界面。 表单、按钮、标签、文本框、数据网格。 如果主战场就在这个世界里,它相当能打。

不过,弱项也很明确。

  • 想大幅统一整个界面的外观
  • 想用样式和模板来控制 UI
  • 想以数据绑定为主处理复杂的状态变化
  • 想把界面逻辑干净地分离出来

这些方面,WPF 或 WinUI 更顺手。

用 WinForms 做大型应用,一不留神就容易变成事件处理器的丛林。 所以如果要选 WinForms,

  • 让每个界面的职责保持精简
  • 以 UserControl 为单位做拆分
  • 有意识地划出相当于 Presenter / ViewModel 的边界
  • 不要把业务逻辑一股脑写进界面事件里

这些从一开始就定下来,后面会省心得多。

避免事件处理器的丛林用WinForms做大型应用容易变成事件处理器的丛林,因此要从一开始就定下让界面职责保持精简、以UserControl为单位拆分、有意识地划出相当于Presenter或ViewModel的边界的图。大型WinForms应用容易变成事件处理器的丛林让界面职责保持精简以UserControl为单位拆分有意识地划出边界不要把业务逻辑写进界面事件

图8:大型 WinForms 应用,把职责拆分的规矩从一开始定下来会省心很多。

另外,实务上相当重要的一点是,并不需要因为想用 Windows App SDK 就放弃 WinForms。 官方也提供了在现有 WinForms 应用里增加 Windows App SDK 功能的引导路径。910

也就是说,WinForms 可以这样选:

  • UI 保持不变
  • 只把需要的 Windows 功能做现代化

这是一个现实的折中点。

保持WinForms不变做现代化的路并不需要因为想用Windows App SDK就放弃WinForms,存在UI保持不变、只把需要的Windows功能做现代化这个现实折中点的图。想用Windows App SDK不需要放弃WinFormsUI保持不变只把需要的功能现代化现实的折中点

图9:WinForms 可以保持 UI 不变,只把需要的 Windows 功能做现代化。

5.2 WPF

从 Windows 桌面的 .NET UI 角度看,WPF 是 平衡性最好的中枢。4

强项很明确。

  • 能用 XAML 声明式地写界面
  • Data Binding 能力强
  • 能用 Style / Template
  • 能用 Command
  • 容易把 View 和逻辑分开
  • 容易梳理中到大型规模的界面

WPF 的官方文档里,数据绑定也被说明为 WPF 的核心功能,命令则被归纳为把输入和执行逻辑分开的机制。67

所以,它适合下面这类项目。

  • 界面数量多的业务应用
  • 列表、详情、编辑、搜索、状态展示很多
  • 多人长期维护的 Windows 应用
  • 想把 View 和逻辑分开
  • 想为将来的改造先把外观和行为的职责分开
  • 用 WinForms 的话界面很快就会变得沉重

全新的 Windows 专属业务应用犹豫不决时, WPF 现在依然是安全的第一候选。 用“WPF 太老了所以不考虑”把它切掉,有点粗暴。

全新业务应用的安全第一候选界面数量多、想把View和逻辑分开、多人长期维护的中到大型Windows业务应用中,WPF现在依然是安全的第一候选的图。界面数量多的业务应用WPF是安全的第一候选想把View和逻辑分开多人长期维护用“太老了所以不考虑”切掉很粗暴

图10:界面数量多、需要长期维护的全新业务应用,WPF 是安全的第一候选。

反过来说,

  • 已经有现有的 WPF 资产
  • 已经积累了 XAML / MVVM 的经验
  • 还没到必须把 Fluent 放在最优先的程度
  • 但想把 UI 设计得比 WinForms 更整洁

这种情况下,WPF 最合理的场景相当常见。

当然,WPF 也有自己的脾气。

  • XAML 雕琢过头就会变得难读
  • 自定义控件和模板叠得太多,维护成本就会变重
  • 过度倒向“什么都用 Binding 解决”的方针,反而更难追踪处理流程

这些确实存在,但与其说是 WPF 不好,不如说是表现力强的工具,用得粗糙反弹也大这么一回事。

WPF 也可以增加 Windows App SDK 的部分功能。 也就是说,存在一条保持 WPF 不变、把 Windows 功能做现代化的路。810

因此,比起

  • 把 WPF 全部丢掉,整体迁移到 WinUI

下面这种做法

  • 把 WPF 迁到现行 .NET 上
  • 只用 Windows App SDK 补上需要的 Windows 功能
  • 从大的新功能开始梳理结构

在实务中更容易赢的场面更多。

比起WPF全面迁移更宜渐进比起把WPF全部丢掉整体迁移到WinUI,把WPF迁到现行.NET、只用Windows App SDK补上需要的Windows功能、从大的新功能开始梳理结构在实务中更容易赢的图。把WPF迁到现行.NET只用SDK补上需要的功能从大的新功能开始梳理比全面迁移更容易赢

图11:WPF 与其全面迁移,不如迁到现行 .NET 再补功能的渐进方式更容易赢。

5.3 WinUI

WinUI 是做全新 Windows 专属应用时的现代首选。12

官方的定位是,

  • 针对最新的硬件和输入方式做了优化
  • 高 DPI
  • 流畅的动画
  • 是 Windows App SDK 的一部分

大致如此。1

所以它适合这类项目。

  • Windows 专属的全新产品
  • UI 的印象和体验本身就很重要
  • 想自然地用上 Fluent
  • 想贴近 Windows 11 当下的位置
  • 想以新的窗口 API 和最新的 Windows 体验为前提

真正有理由选 WinUI 的项目, 大致都是不是“外观新”,而是“想把 Windows 当下的体验带进产品”的项目。

分辨选WinUI的理由真正有理由选WinUI的项目,不是因为外观新,而是想把Windows当下的体验带进产品的项目的图。有理由选WinUI的项目不是“外观新”,而是“把当下的Windows体验带进产品”Windows专属的全新产品、UI印象很重要

图12:选用 WinUI 的理由不在“新”,而在“把当下的 Windows 体验带进来”。

另一方面,也有需要注意的地方。

5.3.1 WinUI 不是“只是新版的 WPF”

因为都用 XAML,看起来很接近,但

  • 底层 API
  • 控件生态
  • 项目结构
  • 部署 / 打包的思路
  • 与 Windows App SDK 的相处方式

都不一样。

也就是说,把它当成可以从 WPF 轻松换过去的目标,是有点危险的。

WinUI不是只是新版的WPF因为都用XAML看起来接近,但底层API、控件生态、项目结构、部署与打包的思路、与Windows App SDK的相处方式都不一样,把它当成可以从WPF轻松换过去的目标很危险的图。都用XAML所以看起来接近但不同的地方很多底层API、控件项目结构、打包与SDK的相处方式当成可轻松替换的目标很危险

图13:即使 XAML 相同,WinUI 也不是可以从 WPF 轻松换过去的目标。

5.3.2 一旦选了 WinUI,发布的问题就会跑到前面来

WinUI 3 应用默认是 packaged 的。 另一方面,Windows App SDK 本身两种形式(packaged / unpackaged)都支持。13142

这里重要的是,

  • 打算怎么发布
  • 运行时怎么部署进去
  • 是否需要 package identity
  • 走企业内部发布、Store、MSIX,还是走现有的 EXE / MSI 路线

这些最好尽早定下来。

不过,只说一句“尽早确认”,也不知道该看什么,所以这里把确认的具体内容放上来。

首先,要定的轴有 2 个。1315

  • packaging:这个应用是否拥有 package identity
  • runtime:Windows App SDK 是以 framework-dependent 方式使用,还是以 self-contained 方式随应用打包
先定下的两个轴WinUI的发布首先要定下应用是否拥有package identity的packaging轴,以及Windows App SDK是用framework-dependent还是self-contained随应用打包的runtime轴这两个轴的图。发布的设计packaging的轴runtime的轴是否拥有package identityframework-dependent还是随应用打包

图14:发布要先定下 packaging 和 runtime 这两个轴。

packaging 侧的选项有 3 个。13

模型 package identity 安装程序 适合的场景
packaged(MSIX) 有 MSIX 取代安装程序 全新开发、Store 发布、用 Intune 等做企业发布
指向外部位置的 packaged(sparse package) 有 直接沿用现有的安装程序 拥有自研安装程序的现有 Win32 / WPF / WinForms
unpackaged 无 MSI / EXE / xcopy 企业内部工具、广泛分发的传统 Win32

接下来,从功能侧判断是否需要 package identity。 官方明确写着“没有 package identity 就无法工作”的功能,例如下面这些。13

  • 后台任务
  • 推送通知(WNS)
  • 共享目标
  • 资源管理器的上下文菜单扩展
  • 文件类型和 URI 方案的关联
  • 启动任务
  • App Service
  • Windows AI API

确认的步骤,按这个顺序在实务中比较顺。

  1. 从需求倒推。 有没有打算使用上面列表里的功能。只要有一个,就需要 packaged 一侧。
  2. 看能不能丢掉现有的安装程序。 如果不想丢,那答案就不是全面迁移到 MSIX,而是指向外部位置的 packaged。现有的二进制部署方式和更新机制都可以保持不变,只把 identity 加上去。13
  3. 在运行时确认。 正在运行的进程有没有 identity,可以用 GetCurrentPackageFullName 来判定。没有 identity 时会返回 APPMODEL_ERROR_NO_PACKAGE。反过来,调用 Windows API 时出现 E_ILLEGAL_METHOD_CALL 或 APPMODEL_ERROR_NO_PACKAGE,就是撞上 package identity 要求的信号。13
  4. 在终端侧确认。 已安装的包可以用 PowerShell 的 Get-AppxPackage 列出来。
  5. 最后决定 runtime。 想用 xcopy 或 zip 分发就选 self-contained,要上架 Store 就以 framework-dependent 为默认路线。15

WinForms / WPF 的发布也很重要,但 WinUI 这边更容易把它推到前台。全新的 WinUI 3 应用默认就是 packaged,什么都不决定的话就会自动走上 MSIX 路线。13 本以为是在决定 UI,实际上却是在决定发布策略,这是这个领域稍微麻烦的地方。

package identity的确认步骤从需求倒推有没有需要package identity的功能,看能不能丢掉现有安装程序,在运行时和终端侧确认,最后决定runtime这5个步骤的确认流程图。1. 从需求倒推2. 看能不能丢掉安装程序3. 在运行时确认4. 在终端侧确认5. 决定runtime不想丢就用指向外部位置的packaged用GetCurrentPackageFullName判定

图15:是否需要 package identity,按需求、安装程序、运行时、终端的顺序确认。

5.3.3 “在现有 WPF / WinForms 里一点点混入 WinUI”,先做实验

这里是期待容易被吹大的地方。 不过,Microsoft 的 FAQ 里也写了这层意思:除非已经做好彻底迁移 UI 框架的准备,否则往往用不了 WinUI。 再进一步,XAML Islands 相关的官方文档虽然给出了往现有桌面应用中嵌入的路径,但 Windows App SDK 1.4 的发布说明里写着,目前主要在 C++ 应用上做过测试,还没有为 WPF / WinForms 提供便捷的封装元素。1011

也就是说,

  • “看起来可以分阶段迁移”
  • “看起来一点点填进去就行”

作为构想很有吸引力,但在把它当成项目主策略之前,最好先做小范围验证。

WinUI 在

  • 从零开始的全新项目
  • 作为 Windows 专属产品打造体验

的时候最有道理。 反过来,把它当作现有 WPF / WinForms 全面替换的承接方,则需要充分的理由和验证。

分阶段迁移在成为主策略前先验证一点点混入WinUI的分阶段迁移作为构想很有吸引力,但FAQ认为除非做好彻底迁移的准备否则往往用不了,XAML Islands也还没有为WPF或WinForms提供便捷封装,因此在成为主策略前要先做小范围验证的图。想一点点混入WinUI作为构想很有吸引力FAQ的意思是以彻底迁移为前提没有面向WPF / WinForms的封装成为主策略前先做小范围验证

图16:“一点点混入 WinUI”,在成为主策略之前先做小范围验证。

6. 常见的判断失误

6.1 “因为最新所以选 WinUI”

这个理由很好懂,但相当危险。

选择新技术的理由,最好用 是否存在只有这项技术才能带来的价值来看。

  • 现代 Windows 体验是不是产品价值
  • 是否想自然地用上 Fluent
  • 是不是全新产品
  • 能不能接受发布 / 运维方面的前提

这些如果是 yes,WinUI 就很有优势。 反过来,如果只是“感觉有前景”,在成本上的解释就比较薄弱。

不按“因为最新”而按价值来选选择新技术的理由应该看是否存在只有这项技术才能带来的价值,如果现代体验是不是产品价值等问题的答案是yes则WinUI有优势,只是感觉有前景的话成本解释就薄弱的图。yes只是“感觉有前景”选择新技术的理由是否存在只有这项技术才有的价值WinUI有优势成本上的解释薄弱

图17:不按“因为最新”,而按是否存在只有这项技术才能带来的价值来选。

6.2 “想用 Windows App SDK 就必须换成 WinUI”

这一点很容易被误解,但并非如此。

Windows App SDK 也可以加到现有的 WPF / WinForms 上。 官方 FAQ 里也归纳说明了,WPF / MFC / WinForms 应用可以使用与 WinUI 无关的 Windows App SDK API。1089

比如,

  • App Lifecycle
  • Windowing
  • Toast Notifications

这类功能,有时可以在保持现有 UI 的前提下引入。10

6.3 “WPF / WinForms 已经完了”

这里同样,最好不要一刀切。

WinForms 和 WPF 在现行 .NET 上都持续有文档和迁移引导,官方也把它们当作现役的 Windows 桌面 UI 来对待。34

作为长期维护的判断材料,比起“文档还在不在”,是否还在持续加入新功能是更好懂的指标。从这个角度看,3 者的情况如下。

  最近的动向 怎么看
WPF .NET 9 中加入了面向 Windows 11 的 Fluent 主题,可以用 ThemeMode 属性在 light / dark / system 之间切换,也支持 Windows 的强调色16 “外观太老所以选 WinUI”这个理由,比以前站不住了
WinForms .NET 9 中加入了深色模式的暂定支持,可以用 Application.SetColorMode 切换。不过这是实验性功能,文档写着正式支持以 .NET 10 为目标。异步相关的 API 也在增加17 新功能确实在持续加入,但其中混有带实验性标记的功能
WinUI / Windows App SDK 按与 .NET 不同的独立发布周期持续更新18 更新很活跃,但需要与 .NET 的版本分开跟进,维护计划里就多出一项

也就是说,从长期维护的角度可以这样读。

  • WPF 和 WinForms 不是“被冻结后放着不管”,而是跟着每年的 .NET 发布持续加入功能。不过 WinForms 的重点功能里有还处在实验阶段的,采用时机需要确认。
  • 一旦选了 WinUI,就要把 .NET 的支持期限和 Windows App SDK 的支持期限分开管理。长期项目中,这一点会悄悄发挥作用。
  • 无论选哪个,都没有“10 年后不改也能跑”的保证,所以一开始就定好要跟进到哪个版本更符合实务。
长期维护的读法WPF和WinForms跟着每年的.NET发布加入功能,而选了WinUI就要把.NET和Windows App SDK的支持期限分开管理,因此要一开始就定好跟进到哪个版本的图。WPF / WinForms跟着.NET发布加入功能WinUI把SDK的期限分开管理一开始就定好跟进到哪里

图18:长期维护要看更新是搭着什么来的,并先定下跟进方针。

尤其在业务应用中,

  • 存量资产
  • 第三方控件
  • 界面数量
  • 报表和打印
  • 设备联动
  • 发布流程

比 UI 框架新不新更重要的情况很常见。

6.4 “既然要改就全面重写”

全面重写不是技术选型,更接近业务判断。

如果已经有现有应用,最先该看的是这几点。

  1. 真正困扰的是什么
  2. 是 UI 的问题,还是架构的问题
  3. 依赖的 DLL / COM / OCX / 报表 / 发布,是不是才是真正的重担
  4. 不把 UI 全换掉,困扰是不是也能解决

重写 UI 很显眼,成本也一样显眼。 而且就算外观变新了,周边的麻烦大体还是留在原地。

全面重写之前要看的4个问题全面重写不是技术选型而更接近业务判断,要先看真正困扰的是什么、是UI还是架构的问题、依赖和发布是不是真正的重担、不改UI能不能解决这4点的图。1. 真正困扰的是什么2. 是UI还是架构3. 依赖和发布是不是重担4. 不改UI能不能解决重写的成本也很显眼

图19:决定全面重写之前,先用 4 个问题确认困扰的真实面目。

6.5 “以后用 XAML Islands 总能搞定”

这种期待可以理解。 但别一开始就把它当成救生艇,会更安全。1011

分阶段迁移,最好先小范围试一下

  • 想嵌入的控件到底是什么
  • 焦点、输入、DPI、主题会变成什么样
  • 那套宿主结构实际上是否稳定

这几点。

XAML Islands要先小范围试分阶段迁移要先小范围试一下想嵌入的控件是什么、焦点与输入与DPI与主题会怎样、宿主结构是否稳定,不要一开始就把它当成救生艇的图。“以后总能搞定”的期待想嵌入的控件是什么焦点、输入、DPI、主题宿主结构是否稳定先小范围试

图20:XAML Islands 别当成救生艇,先把这 3 点小范围试一下。

7. 以现有应用为前提时的看法

这里比起全新项目,现有应用更重要。

7.1 已经有现有 WinForms 的话

在直接跳到 WinUI 之前,先确认这几点。

  • 能不能迁到现行 .NET
  • 是否需要做 64 位化
  • 能不能把 async / await、异常处理、配置、日志梳理清楚
  • 能不能通过界面拆分或 UserControl 化来提升可维护性
  • 能不能只用 Windows App SDK 补上需要的 Windows 功能

看起来像是 WinForms 的问题,实际上往往只是

  • 界面和逻辑混在一起
  • 线程边界划得粗糙
  • 配置 / 文件 / COM / 数据库的职责挤在一起

而已,这种情况并不罕见。

这种情况下,就算搬到 WinUI,问题也只是换了个名字继续留着。

问题换个名字继续留着看起来像WinForms的问题,实际往往是界面和逻辑混在一起、线程边界粗糙、职责挤在一起造成的,这种情况下搬到WinUI问题也只是换个名字继续留着的图。看起来像WinForms的问题其实是结构的问题界面和逻辑混在一起线程边界粗糙职责挤在一起搬到WinUI也只是换个名字留着

图21:看起来像 UI 问题的结构问题,换了框架也依然留着。

7.2 已经有现有 WPF 的话

WPF 容易复用现有资产。

  • XAML 资产
  • Binding
  • Style / Template
  • Command
  • MVVM

要丢掉这些,理由应该相当明确才行。

比如,

  • 想全面更新产品 UI
  • 想以 Fluent 为主轴
  • 把新模块作为独立产品切出去
  • 作为 Windows 专属产品想贴近新的体验

这些可以成为考虑 WinUI 的理由。 但如果只是“WPF 太老了”,理由就很薄弱。

7.3 真正沉重的往往在 UI 之外

在实务中,难受的意外就在这些地方。

  • ActiveX / OCX
  • COM interop
  • 自研报表
  • 打印
  • Excel / Office 联动
  • 原生 DLL
  • 32 位 / 64 位的错位
  • 安装程序、权限、更新、签名

轻视这些的话,就算只把 UI 做漂亮,整个项目也不会变轻松。

所以在现有应用的迁移中, 先不要只盯着 UI 框架,而要连依赖边界一起盘点才是先手。

连依赖边界一起盘点实务中沉重的往往是ActiveX和COM、报表和打印、原生DLL、安装程序和更新这些UI之外的部分,因此比起只盯着UI框架,连依赖边界一起盘点才是先手的图。ActiveX / COM interop真正沉重的在UI之外报表、打印、Office联动安装程序、权限、更新、签名先连依赖边界一起盘点只把UI做漂亮也不会变轻松

图22:迁移中真正沉重的是 UI 之外的依赖,先做盘点。

8. 犹豫不决时最后要看的 5 个问题

如果最终还是拿不定主意,就按顺序把这 5 个问题套上去。

8.1 存量资产规模大吗

  • 大 → 基本维持现有技术路线
  • 小 / 没有 → 按全新项目来选型

8.2 这个应用里“Windows 风格的现代体验”是必需的吗

  • 必需 → WinUI 有优势
  • 没到那个程度 → 确认 WPF / WinForms 是否已经够用

8.3 界面是以标准表单为主,还是需要 XAML 式的表现力

  • 以标准表单为主 → WinForms
  • 样式 / 模板 / Binding / MVVM 很重要 → WPF

8.4 想要的是 UI 的全面更新,还是 Windows 功能的增加

  • UI 的全面更新 → 考虑 WinUI
  • 只是增加功能 → 先考虑现行 WPF / WinForms + Windows App SDK

8.5 发布 / 更新 / 运维怎么做,能不能提前说清楚

  • 还比较模糊 → 选 WinUI 就要尽早把 packaging / deployment 敲定
  • 想紧密贴合现有运维 → WPF / WinForms 的摩擦往往更少
最后要看的5个问题的流程按存量资产是否规模大、现代体验是否必需、是以标准表单为主还是需要表现力、发布与更新与运维能否说清楚的顺序把问题套上去,逐步缩小选项的流程图。大小、没有必需没到那个程度是表现力更重要存量资产规模大吗基本维持现有技术路线现代体验是必需的吗WinUI有优势是以标准表单为主吗WinFormsWPF只是增加功能就先考虑SDK尽早敲定packaging和发布

图23:犹豫时按存量资产、体验、界面性质的顺序把问题套上去逐步缩小。

靠这 5 个问题就能收窄很多。 最后粗略总结一下,大致是这样。

  • 快速做出的企业内部表单 → WinForms
  • 长期成长的 Windows 业务应用 → WPF
  • 全新的现代 Windows 产品 UI → WinUI
  • 复用现有资产、只把 Windows 功能现代化 → 现行框架 + Windows App SDK

9. 总结

WinForms、WPF、WinUI 的选型, 不是一场按新旧排序、直接取最右边那个的游戏。

首先该看的是这 4 点。

  1. 存量资产在哪里
  2. 界面是以表单为主,还是以表现力为主
  3. Windows 风格的现代 UI 是不是产品需求
  4. 发布 / 更新 / 运维怎么转起来

这 4 点看清楚了,方针大致就定了。

总结的4个问题存量资产在哪里、界面是以表单为主还是以表现力为主、现代UI是不是产品需求、发布与更新与运维怎么转起来这4点看清楚了方针大致就定了的图。存量资产方针大致就定了界面的性质现代UI需求发布和运维

图24:这 4 个问题看清楚了,框架的方针大致就定了。

  • 手里有大量现有 WinForms,就先继续用 WinForms
  • 手里有大量现有 WPF,就先继续用 WPF
  • 全新项目以标准表单为主,就选 WinForms
  • 全新的中到大型 Windows 业务应用,就选 WPF
  • 全新项目里现代 Windows 体验本身就是需求,就选 WinUI
  • 只是想用 Windows App SDK,就不要一上来全部换成 WinUI

最想避免的是这 3 种做法。

  • 因为旧就丢掉
  • 因为新就选它
  • 抱着中途总会有办法的心态开工

Windows 桌面这个领域,比起外观,资产、发布、运维、依赖关系才是更重的部分。 所以比起新鲜感,更看重与存量资产、发布、运维之间摩擦更少的选择,在实务上更合适。

10. 参考资料

  1. Microsoft Learn,“WinUI 3 - Windows apps” / Microsoft Learn,“Modernize your desktop apps for Windows” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

  2. Microsoft Learn,“Windows App SDK” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  3. Microsoft Learn,“Windows 窗体是什么 - Windows Forms” ↩ ↩2 ↩3 ↩4 ↩5

  4. Microsoft Learn,“Windows Presentation Foundation 是什么 - WPF” ↩ ↩2 ↩3 ↩4 ↩5

  5. Microsoft Learn,“What is Windows Forms Designer?” ↩ ↩2

  6. Microsoft Learn,“Data binding overview - WPF” ↩ ↩2 ↩3

  7. Microsoft Learn,“Commanding Overview - WPF” ↩ ↩2 ↩3

  8. Microsoft Learn,“在 WPF 应用中使用 Windows App SDK” ↩ ↩2 ↩3

  9. Microsoft Learn,“Use the Windows App SDK in a Windows Forms (WinForms) app” ↩ ↩2 ↩3

  10. Microsoft Learn,“面向 Windows 开发者的 FAQ” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9

  11. Microsoft Learn,“Windows App SDK 1.4 release notes” / Microsoft Learn,“Windows App SDK” ↩ ↩2 ↩3

  12. Microsoft Learn,“Windows data binding and MVVM” ↩

  13. Microsoft Learn,“Packaging overview - Windows apps” / Microsoft Learn,“Grant package identity by packaging with external location” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

  14. Microsoft Learn,“Quick start: Set up your environment and create a WinUI 3 project” ↩

  15. Microsoft Learn,“Package and deploy Windows apps overview” ↩ ↩2

  16. Microsoft Learn,“What’s new in WPF for .NET 9” ↩

  17. Microsoft Learn,“What’s new in WinForms for .NET 9” ↩

  18. Microsoft Learn,“Windows App SDK release channels” ↩

共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。

与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。

本文与以下服务页面相关联,欢迎从最接近的入口查看。

常见问题

汇总了咨询这一主题时常见的问题。

WinUI 3 和 WPF 有什么区别?
两者都用 XAML,但 WinUI 并不是只是新版的 WPF。底层 API、控件生态、项目结构、部署与打包的思路、和 Windows App SDK 的相处方式都不一样。WPF 是具备与分辨率无关的矢量绘图、数据绑定、样式与模板、命令的 UI 框架,面向中到大型业务应用;WinUI 则是 Windows App SDK 的一部分,以 Fluent、高 DPI、最新 Windows 体验为前提的现代 UI 框架。把它当成可以从 WPF 轻松换过去的目标很危险。
全新开发该选 WinForms、WPF 还是 WinUI?
取决于界面的性质和产品需求。如果是以标准控件、录入表单为主的小到中型企业内部工具,想快速做出来,WinForms 现在依然很能打。如果是界面数量多、想踏实用好数据绑定、样式、模板、MVVM 的中到大型业务应用,WPF 大多数情况下最稳妥。如果是 Windows 专属的全新产品,而且 Fluent 和现代 Windows 体验直接关系到产品价值,那么 WinUI 很有优势。存量资产规模大的场合,先以延续原有技术路线为基本前提来看。
WPF 和 WinForms 已经过时了吗?
不要一刀切地下结论。WinForms 和 WPF 在现行 .NET 上都持续有文档和迁移引导,官方也把它们当作现役的 Windows 桌面 UI 来对待。尤其在业务应用中,存量资产、第三方控件、报表与打印、设备联动、发布流程往往比 UI 框架新不新更重要。即便是全新项目,WinForms 或 WPF 成为摩擦最小的选择也并不罕见。
要用上最新的 Windows 功能,就必须迁移到 WinUI 吗?
不必。Windows App SDK 和 WinUI 不是一回事,WinUI 是 Windows App SDK 中的 UI 框架部分。Windows App SDK 本身也可以加到 WPF / WinForms / Win32 的现有应用里,App Lifecycle、Windowing、Toast Notifications 这类功能,有时可以在保持现有 UI 的前提下引入。也就是说,存在保持现有 WPF / WinForms 不变、只把需要的 Windows 功能现代化的路径,并不一定要整体迁移 UI。

作者简介

本文作者的个人简介页面。

Go Komura

小村软件有限公司 代表

以 Windows 软件开发、技术咨询与故障排查为中心,擅长难以复现的故障调查,以及既有资产仍在运行的项目。

返回博客列表