引用本文(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
这类模糊的选法。
flowchart TB
accTitle: 模糊选法的危险
accDescr: 因为最新所以选WinUI、因为最熟悉所以选WinForms、因为感觉居中所以选WPF这类模糊的选法很危险,实务中要用更明确的维度来看的图。
w1["因为新所以选WinUI"] --> w4["模糊的选法"]
w2["因为熟悉所以选WinForms"] --> w4
w3["因为居中所以选WPF"] --> w4
w4 --> w5["实务中用明确的维度来看"]
图1:不用“新、熟悉、居中”来选,而是用明确的维度来选。
在实务中,该看的维度更明确一些。
- 是全新开发,还是现有资产的延伸
- 界面是以录入表单为主,还是需要表现力
- Windows 风格的现代 UI 本身是不是产品价值
- 发布、更新、企业内部运维怎么处理
- 是以 Windows Forms Designer 为中心的开发方式,还是以 XAML/MVVM 为中心的开发方式
本文把这些整理成一张判断表。 另外,本文所说的 WinUI 主要指 WinUI 3 + Windows App SDK。12
还有,这 3 个框架全都是 Windows 专属的。 如果 macOS / Linux 也在视野之内,那问题的设定本身就不一样了。341
flowchart TB
accTitle: 三者都是 Windows 专属
accDescr: WinForms、WPF、WinUI都是Windows专属的,如果macOS或Linux也在视野之内,问题的设定本身就不一样的图。
t1["WinForms"] --> t4["全都是 Windows 专属"]
t2["WPF"] --> t4
t3["WinUI"] --> t4
t4 -.-> t5["macOS / 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
概括起来,大致就是这么几条。
- 存量资产规模大,就先保住那条技术路线
- 全新项目要快速做标准表单,就选 WinForms
- 全新项目要做长期成长的 Windows 业务应用,就选 WPF
- 全新项目里现代 Windows UI 本身就是需求,就选 WinUI
- 只是想用 Windows App SDK,就不要一上来全部换成 WinUI
框架选型既是 UI 技术的选型,同时也是 发布、运维、学习成本、迁移成本的选型。 如果只用“新 / 旧”来决定,代价会在后续的发布设计和维护成本上反弹回来。
flowchart TB
accTitle: 先说结论的决定方式
accDescr: 存量资产规模大就先保住那条技术路线,全新项目要快速做标准表单就选WinForms,要做长期成长的Windows业务应用就选WPF,现代Windows UI本身是需求就选WinUI的决定方式的图。
r1{"存量资产是否规模大"} -->|"是"| r2["先保住那条技术路线"]
r1 -->|"否,全新项目"| r3{"是否以标准表单为主"}
r3 -->|"是"| r4["WinForms"]
r3 -->|"否"| r5{"现代UI本身是否是需求"}
r5 -->|"否"| r6["WPF,长期成长的业务应用"]
r5 -->|"是"| r7["WinUI"]
r7 -.-> r8["只为用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”和“要不要增加功能”就会被当成同一件事,结论很难收敛。
flowchart TB
accTitle: Windows App SDK和WinUI不是一回事
accDescr: WinUI是Windows App SDK的UI框架部分,而Windows App SDK本身也可以加到WPF、WinForms、Win32的现有应用里,因此使用WinUI的判断和使用SDK功能的判断是不同的图。
sdk["Windows App SDK"] --> ui["WinUI,它的UI框架部分"]
sdk -.-> ex["也可以加到 WPF / WinForms / Win32"]
ui --> d1["“使用WinUI”的判断"]
ex --> d2["“使用SDK功能”的判断"]
d1 --> d3["看似相似其实是不同的判断"]
d2 --> d3
图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 专属 |
光靠这张表大体就够了,但还剩下两个容易纠结的点。
- 全新的 Windows 业务应用,该偏向 WinForms 还是 WPF
- 已经有现有 WPF / WinForms,还该不该转向 WinUI
这两点,对照后面按维度划分的对比表来考虑就容易判断了。
flowchart TB
accTitle: 判断表之后仍留下的两个纠结
accDescr: 只靠一页判断表,还会剩下全新Windows业务应用该偏向WinForms还是WPF,以及已经有现有WPF或WinForms还该不该转向WinUI这两点,需要用后面的对比表来考虑的图。
hyo["一页判断表"] --> n1["全新业务应用是WinForms还是WPF"]
hyo --> n2["已经有存量还要不要转向WinUI"]
n1 --> hik["用按维度划分的对比表来考虑"]
n2 --> hik
图5:判断表之后剩下的两个纠结,用按维度划分的对比表来考虑。
4. 按维度划分的对比表
这里不是官方的优劣评比,而是相当偏实务的对比。
| 维度 | WinForms | WPF | WinUI |
|---|---|---|---|
| 快速做小型录入表单 | ◎ | ○ | ○ |
| 以标准控件为主的企业内部工具 | ◎ | ○ | △~○ |
| 与数据绑定 / MVVM 的契合度 | △ | ◎ | ○~◎ |
| 样式 / 模板 / 界面的表现力 | △ | ◎ | ◎ |
| 与现有 Windows 桌面资产的亲和性 | ◎ | ○ | △ |
| 现代 Windows 风格 | △ | ○ | ◎ |
| 现有界面的延续维护、分阶段改造 | ◎ | ◎ | △ |
| 只想增加 Windows App SDK 的功能 | ○ | ○ | ◎ |
| 发布 / 更新 / 运维设计的轻量程度 | ○ | ○ | △~○ |
| 打造“全新且能长期成长的 Windows 专属产品 UI” | △ | ○ | ◎ |
看表的窍门不是找谁最强,而是找谁的摩擦最少。
比如,
- 企业内部的设置工具
- 设备设置界面
- 列表、明细、搜索、设置、按钮
- 比起外观,更看重运维的稳定和改造速度
这类场景下,WinForms 现在依然足够合理。
反过来,
- 界面数量多
- 显示状态切换频繁
- 想把 View 和逻辑分开
- 想让数据的变化自然地反映到 UI 上
- 想用样式 / 模板统一管控 UI
而且,
- 想以 Windows 11 风格的外观为前提
- 想踏实用好 Fluent
- 想以高 DPI、触控、现代窗口 API 为前提
- 是全新项目,而且作为 Windows 专属产品,UI 给人的印象也很重要
flowchart TB
accTitle: 按摩擦少来选
accDescr: 窍门不是找谁最强而是找谁的摩擦最少,以标准控件为主的企业内部工具适合WinForms,界面数量多且想用MVVM的项目适合WPF,以Fluent和最新Windows体验为前提的项目适合WinUI的图。
k0["谁的摩擦最少"] --> k1["企业内部工具、以标准控件为主"]
k0 --> k2["界面数量多且想用MVVM"]
k0 --> k3["以Fluent、最新Windows体验为前提"]
k1 --> k4["WinForms"]
k2 --> k5["WPF"]
k3 --> k6["WinUI"]
图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 更轻松,这就是这个差别在实务上的含义。
flowchart TB
accTitle: 值的流向的差别
accDescr: WinForms中事件处理器直接从界面控件取出值再传给服务,而WPF中Binding把View和ViewModel连接起来,由不知道界面存在的ViewModel调用服务,两者值的流向不同的图。
subgraph wf["WinForms"]
a1["View的控件"] --> a2["事件处理器"]
a2 --> a3["直接调用服务"]
end
subgraph wp["WPF"]
b1["View的XAML"] --> b2["Binding"]
b2 --> b3["ViewModel"]
b3 --> b4["调用服务"]
end
a3 -.-> c1["3个界面时更快"]
b4 -.-> c2["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 的边界
- 不要把业务逻辑一股脑写进界面事件里
这些从一开始就定下来,后面会省心得多。
flowchart TB
accTitle: 避免事件处理器的丛林
accDescr: 用WinForms做大型应用容易变成事件处理器的丛林,因此要从一开始就定下让界面职责保持精简、以UserControl为单位拆分、有意识地划出相当于Presenter或ViewModel的边界的图。
mo["大型WinForms应用"] --> ha["容易变成事件处理器的丛林"]
ha --> p1["让界面职责保持精简"]
ha --> p2["以UserControl为单位拆分"]
ha --> p3["有意识地划出边界"]
p3 -.-> p4["不要把业务逻辑写进界面事件"]
图8:大型 WinForms 应用,把职责拆分的规矩从一开始定下来会省心很多。
另外,实务上相当重要的一点是,并不需要因为想用 Windows App SDK 就放弃 WinForms。 官方也提供了在现有 WinForms 应用里增加 Windows App SDK 功能的引导路径。910
也就是说,WinForms 可以这样选:
- UI 保持不变
- 只把需要的 Windows 功能做现代化
这是一个现实的折中点。
flowchart TB
accTitle: 保持WinForms不变做现代化的路
accDescr: 并不需要因为想用Windows App SDK就放弃WinForms,存在UI保持不变、只把需要的Windows功能做现代化这个现实折中点的图。
g1["想用Windows App SDK"] --> g2["不需要放弃WinForms"]
g2 --> g3["UI保持不变"]
g2 --> g4["只把需要的功能现代化"]
g3 --> g5["现实的折中点"]
g4 --> g5
图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 太老了所以不考虑”把它切掉,有点粗暴。
flowchart TB
accTitle: 全新业务应用的安全第一候选
accDescr: 界面数量多、想把View和逻辑分开、多人长期维护的中到大型Windows业务应用中,WPF现在依然是安全的第一候选的图。
j1["界面数量多的业务应用"] --> j4["WPF是安全的第一候选"]
j2["想把View和逻辑分开"] --> j4
j3["多人长期维护"] --> j4
j4 -.-> j5["用“太老了所以不考虑”切掉很粗暴"]
图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 功能
- 从大的新功能开始梳理结构
在实务中更容易赢的场面更多。
flowchart TB
accTitle: 比起WPF全面迁移更宜渐进
accDescr: 比起把WPF全部丢掉整体迁移到WinUI,把WPF迁到现行.NET、只用Windows App SDK补上需要的Windows功能、从大的新功能开始梳理结构在实务中更容易赢的图。
z1["把WPF迁到现行.NET"] --> z2["只用SDK补上需要的功能"]
z2 --> z3["从大的新功能开始梳理"]
z3 -.-> z4["比全面迁移更容易赢"]
图11:WPF 与其全面迁移,不如迁到现行 .NET 再补功能的渐进方式更容易赢。
5.3 WinUI
WinUI 是做全新 Windows 专属应用时的现代首选。12
官方的定位是,
- 针对最新的硬件和输入方式做了优化
- 高 DPI
- 流畅的动画
- 是 Windows App SDK 的一部分
大致如此。1
所以它适合这类项目。
- Windows 专属的全新产品
- UI 的印象和体验本身就很重要
- 想自然地用上 Fluent
- 想贴近 Windows 11 当下的位置
- 想以新的窗口 API 和最新的 Windows 体验为前提
真正有理由选 WinUI 的项目, 大致都是不是“外观新”,而是“想把 Windows 当下的体验带进产品”的项目。
flowchart TB
accTitle: 分辨选WinUI的理由
accDescr: 真正有理由选WinUI的项目,不是因为外观新,而是想把Windows当下的体验带进产品的项目的图。
y1["有理由选WinUI的项目"] --> y2["不是“外观新”,而是"]
y2 --> y3["“把当下的Windows体验带进产品”"]
y3 -.-> y4["Windows专属的全新产品、UI印象很重要"]
图12:选用 WinUI 的理由不在“新”,而在“把当下的 Windows 体验带进来”。
另一方面,也有需要注意的地方。
5.3.1 WinUI 不是“只是新版的 WPF”
因为都用 XAML,看起来很接近,但
- 底层 API
- 控件生态
- 项目结构
- 部署 / 打包的思路
- 与 Windows App SDK 的相处方式
都不一样。
也就是说,把它当成可以从 WPF 轻松换过去的目标,是有点危险的。
flowchart TB
accTitle: WinUI不是只是新版的WPF
accDescr: 因为都用XAML看起来接近,但底层API、控件生态、项目结构、部署与打包的思路、与Windows App SDK的相处方式都不一样,把它当成可以从WPF轻松换过去的目标很危险的图。
u1["都用XAML所以看起来接近"] --> u2["但不同的地方很多"]
u2 --> u3["底层API、控件"]
u2 --> u4["项目结构、打包"]
u2 --> u5["与SDK的相处方式"]
u5 -.-> u6["当成可轻松替换的目标很危险"]
图13:即使 XAML 相同,WinUI 也不是可以从 WPF 轻松换过去的目标。
5.3.2 一旦选了 WinUI,发布的问题就会跑到前面来
WinUI 3 应用默认是 packaged 的。 另一方面,Windows App SDK 本身两种形式(packaged / unpackaged)都支持。13142
这里重要的是,
- 打算怎么发布
- 运行时怎么部署进去
- 是否需要 package identity
- 走企业内部发布、Store、MSIX,还是走现有的 EXE / MSI 路线
这些最好尽早定下来。
不过,只说一句“尽早确认”,也不知道该看什么,所以这里把确认的具体内容放上来。
- packaging:这个应用是否拥有 package identity
- runtime:Windows App SDK 是以 framework-dependent 方式使用,还是以 self-contained 方式随应用打包
flowchart TB
accTitle: 先定下的两个轴
accDescr: WinUI的发布首先要定下应用是否拥有package identity的packaging轴,以及Windows App SDK是用framework-dependent还是self-contained随应用打包的runtime轴这两个轴的图。
h1["发布的设计"] --> h2["packaging的轴"]
h1 --> h3["runtime的轴"]
h2 -.-> h4["是否拥有package identity"]
h3 -.-> h5["framework-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
确认的步骤,按这个顺序在实务中比较顺。
- 从需求倒推。 有没有打算使用上面列表里的功能。只要有一个,就需要 packaged 一侧。
- 看能不能丢掉现有的安装程序。 如果不想丢,那答案就不是全面迁移到 MSIX,而是指向外部位置的 packaged。现有的二进制部署方式和更新机制都可以保持不变,只把 identity 加上去。13
- 在运行时确认。 正在运行的进程有没有 identity,可以用
GetCurrentPackageFullName来判定。没有 identity 时会返回APPMODEL_ERROR_NO_PACKAGE。反过来,调用 Windows API 时出现E_ILLEGAL_METHOD_CALL或APPMODEL_ERROR_NO_PACKAGE,就是撞上 package identity 要求的信号。13 - 在终端侧确认。 已安装的包可以用 PowerShell 的
Get-AppxPackage列出来。 - 最后决定 runtime。 想用 xcopy 或 zip 分发就选 self-contained,要上架 Store 就以 framework-dependent 为默认路线。15
WinForms / WPF 的发布也很重要,但 WinUI 这边更容易把它推到前台。全新的 WinUI 3 应用默认就是 packaged,什么都不决定的话就会自动走上 MSIX 路线。13 本以为是在决定 UI,实际上却是在决定发布策略,这是这个领域稍微麻烦的地方。
flowchart TB
accTitle: package identity的确认步骤
accDescr: 从需求倒推有没有需要package identity的功能,看能不能丢掉现有安装程序,在运行时和终端侧确认,最后决定runtime这5个步骤的确认流程图。
s1["1. 从需求倒推"] --> s2["2. 看能不能丢掉安装程序"]
s2 --> s3["3. 在运行时确认"]
s3 --> s4["4. 在终端侧确认"]
s4 --> s5["5. 决定runtime"]
s2 -.-> s6["不想丢就用指向外部位置的packaged"]
s3 -.-> s7["用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 全面替换的承接方,则需要充分的理由和验证。
flowchart TB
accTitle: 分阶段迁移在成为主策略前先验证
accDescr: 一点点混入WinUI的分阶段迁移作为构想很有吸引力,但FAQ认为除非做好彻底迁移的准备否则往往用不了,XAML Islands也还没有为WPF或WinForms提供便捷封装,因此在成为主策略前要先做小范围验证的图。
v1["想一点点混入WinUI"] --> v2["作为构想很有吸引力"]
v2 --> v3["FAQ的意思是以彻底迁移为前提"]
v3 --> v4["没有面向WPF / WinForms的封装"]
v4 --> v5["成为主策略前先做小范围验证"]
图16:“一点点混入 WinUI”,在成为主策略之前先做小范围验证。
6. 常见的判断失误
6.1 “因为最新所以选 WinUI”
这个理由很好懂,但相当危险。
选择新技术的理由,最好用 是否存在只有这项技术才能带来的价值来看。
- 现代 Windows 体验是不是产品价值
- 是否想自然地用上 Fluent
- 是不是全新产品
- 能不能接受发布 / 运维方面的前提
这些如果是 yes,WinUI 就很有优势。 反过来,如果只是“感觉有前景”,在成本上的解释就比较薄弱。
flowchart TB
accTitle: 不按“因为最新”而按价值来选
accDescr: 选择新技术的理由应该看是否存在只有这项技术才能带来的价值,如果现代体验是不是产品价值等问题的答案是yes则WinUI有优势,只是感觉有前景的话成本解释就薄弱的图。
q0["选择新技术的理由"] --> q1{"是否存在只有这项技术才有的价值"}
q1 -->|"yes"| q2["WinUI有优势"]
q1 -->|"只是“感觉有前景”"| q3["成本上的解释薄弱"]
图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 年后不改也能跑”的保证,所以一开始就定好要跟进到哪个版本更符合实务。
flowchart TB
accTitle: 长期维护的读法
accDescr: WPF和WinForms跟着每年的.NET发布加入功能,而选了WinUI就要把.NET和Windows App SDK的支持期限分开管理,因此要一开始就定好跟进到哪个版本的图。
m1["WPF / WinForms"] --> m2["跟着.NET发布加入功能"]
m3["WinUI"] --> m4["把SDK的期限分开管理"]
m2 --> m5["一开始就定好跟进到哪里"]
m4 --> m5
图18:长期维护要看更新是搭着什么来的,并先定下跟进方针。
尤其在业务应用中,
- 存量资产
- 第三方控件
- 界面数量
- 报表和打印
- 设备联动
- 发布流程
比 UI 框架新不新更重要的情况很常见。
6.4 “既然要改就全面重写”
全面重写不是技术选型,更接近业务判断。
如果已经有现有应用,最先该看的是这几点。
- 真正困扰的是什么
- 是 UI 的问题,还是架构的问题
- 依赖的 DLL / COM / OCX / 报表 / 发布,是不是才是真正的重担
- 不把 UI 全换掉,困扰是不是也能解决
重写 UI 很显眼,成本也一样显眼。 而且就算外观变新了,周边的麻烦大体还是留在原地。
flowchart TB
accTitle: 全面重写之前要看的4个问题
accDescr: 全面重写不是技术选型而更接近业务判断,要先看真正困扰的是什么、是UI还是架构的问题、依赖和发布是不是真正的重担、不改UI能不能解决这4点的图。
r1["1. 真正困扰的是什么"] --> r2["2. 是UI还是架构"]
r2 --> r3["3. 依赖和发布是不是重担"]
r3 --> r4["4. 不改UI能不能解决"]
r4 -.-> r5["重写的成本也很显眼"]
图19:决定全面重写之前,先用 4 个问题确认困扰的真实面目。
6.5 “以后用 XAML Islands 总能搞定”
这种期待可以理解。 但别一开始就把它当成救生艇,会更安全。1011
分阶段迁移,最好先小范围试一下
- 想嵌入的控件到底是什么
- 焦点、输入、DPI、主题会变成什么样
- 那套宿主结构实际上是否稳定
这几点。
flowchart TB
accTitle: XAML Islands要先小范围试
accDescr: 分阶段迁移要先小范围试一下想嵌入的控件是什么、焦点与输入与DPI与主题会怎样、宿主结构是否稳定,不要一开始就把它当成救生艇的图。
p0["“以后总能搞定”的期待"] --> p1["想嵌入的控件是什么"]
p0 --> p2["焦点、输入、DPI、主题"]
p0 --> p3["宿主结构是否稳定"]
p1 --> p4["先小范围试"]
p2 --> p4
p3 --> p4
图20:XAML Islands 别当成救生艇,先把这 3 点小范围试一下。
7. 以现有应用为前提时的看法
这里比起全新项目,现有应用更重要。
7.1 已经有现有 WinForms 的话
在直接跳到 WinUI 之前,先确认这几点。
- 能不能迁到现行 .NET
- 是否需要做 64 位化
- 能不能把 async / await、异常处理、配置、日志梳理清楚
- 能不能通过界面拆分或 UserControl 化来提升可维护性
- 能不能只用 Windows App SDK 补上需要的 Windows 功能
看起来像是 WinForms 的问题,实际上往往只是
- 界面和逻辑混在一起
- 线程边界划得粗糙
- 配置 / 文件 / COM / 数据库的职责挤在一起
而已,这种情况并不罕见。
这种情况下,就算搬到 WinUI,问题也只是换了个名字继续留着。
flowchart TB
accTitle: 问题换个名字继续留着
accDescr: 看起来像WinForms的问题,实际往往是界面和逻辑混在一起、线程边界粗糙、职责挤在一起造成的,这种情况下搬到WinUI问题也只是换个名字继续留着的图。
e1["看起来像WinForms的问题"] --> e2["其实是结构的问题"]
e2 --> e3["界面和逻辑混在一起"]
e2 --> e4["线程边界粗糙"]
e2 --> e5["职责挤在一起"]
e4 --> e6["搬到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 框架,而要连依赖边界一起盘点才是先手。
flowchart TB
accTitle: 连依赖边界一起盘点
accDescr: 实务中沉重的往往是ActiveX和COM、报表和打印、原生DLL、安装程序和更新这些UI之外的部分,因此比起只盯着UI框架,连依赖边界一起盘点才是先手的图。
d1["ActiveX / COM interop"] --> d4["真正沉重的在UI之外"]
d2["报表、打印、Office联动"] --> d4
d3["安装程序、权限、更新、签名"] --> d4
d4 --> d5["先连依赖边界一起盘点"]
d5 -.-> d6["只把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 的摩擦往往更少
flowchart TB
accTitle: 最后要看的5个问题的流程
accDescr: 按存量资产是否规模大、现代体验是否必需、是以标准表单为主还是需要表现力、发布与更新与运维能否说清楚的顺序把问题套上去,逐步缩小选项的流程图。
f1{"存量资产规模大吗"} -->|"大"| f2["基本维持现有技术路线"]
f1 -->|"小、没有"| f3{"现代体验是必需的吗"}
f3 -->|"必需"| f4["WinUI有优势"]
f3 -->|"没到那个程度"| f5{"是以标准表单为主吗"}
f5 -->|"是"| f6["WinForms"]
f5 -->|"表现力更重要"| f7["WPF"]
f2 -.-> f8["只是增加功能就先考虑SDK"]
f4 -.-> f9["尽早敲定packaging和发布"]
图23:犹豫时按存量资产、体验、界面性质的顺序把问题套上去逐步缩小。
靠这 5 个问题就能收窄很多。 最后粗略总结一下,大致是这样。
- 快速做出的企业内部表单 → WinForms
- 长期成长的 Windows 业务应用 → WPF
- 全新的现代 Windows 产品 UI → WinUI
- 复用现有资产、只把 Windows 功能现代化 → 现行框架 + Windows App SDK
9. 总结
WinForms、WPF、WinUI 的选型, 不是一场按新旧排序、直接取最右边那个的游戏。
首先该看的是这 4 点。
- 存量资产在哪里
- 界面是以表单为主,还是以表现力为主
- Windows 风格的现代 UI 是不是产品需求
- 发布 / 更新 / 运维怎么转起来
这 4 点看清楚了,方针大致就定了。
flowchart TB
accTitle: 总结的4个问题
accDescr: 存量资产在哪里、界面是以表单为主还是以表现力为主、现代UI是不是产品需求、发布与更新与运维怎么转起来这4点看清楚了方针大致就定了的图。
n1["存量资产"] --> n5["方针大致就定了"]
n2["界面的性质"] --> n5
n3["现代UI需求"] --> n5
n4["发布和运维"] --> n5
图24:这 4 个问题看清楚了,框架的方针大致就定了。
- 手里有大量现有 WinForms,就先继续用 WinForms
- 手里有大量现有 WPF,就先继续用 WPF
- 全新项目以标准表单为主,就选 WinForms
- 全新的中到大型 Windows 业务应用,就选 WPF
- 全新项目里现代 Windows 体验本身就是需求,就选 WinUI
- 只是想用 Windows App SDK,就不要一上来全部换成 WinUI
最想避免的是这 3 种做法。
- 因为旧就丢掉
- 因为新就选它
- 抱着中途总会有办法的心态开工
Windows 桌面这个领域,比起外观,资产、发布、运维、依赖关系才是更重的部分。 所以比起新鲜感,更看重与存量资产、发布、运维之间摩擦更少的选择,在实务上更合适。
10. 参考资料
-
Microsoft Learn,“WinUI 3 - Windows apps” / Microsoft Learn,“Modernize your desktop apps for Windows” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Microsoft Learn,“Windows 窗体是什么 - Windows Forms” ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn,“Windows Presentation Foundation 是什么 - WPF” ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn,“What is Windows Forms Designer?” ↩ ↩2
-
Microsoft Learn,“Data binding overview - WPF” ↩ ↩2 ↩3
-
Microsoft Learn,“Commanding Overview - WPF” ↩ ↩2 ↩3
-
Microsoft Learn,“在 WPF 应用中使用 Windows App SDK” ↩ ↩2 ↩3
-
Microsoft Learn,“Use the Windows App SDK in a Windows Forms (WinForms) app” ↩ ↩2 ↩3
-
Microsoft Learn,“面向 Windows 开发者的 FAQ” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Microsoft Learn,“Windows App SDK 1.4 release notes” / Microsoft Learn,“Windows App SDK” ↩ ↩2 ↩3
-
Microsoft Learn,“Windows data binding and MVVM” ↩
-
Microsoft Learn,“Packaging overview - Windows apps” / Microsoft Learn,“Grant package identity by packaging with external location” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Microsoft Learn,“Quick start: Set up your environment and create a WinUI 3 project” ↩
-
Microsoft Learn,“Package and deploy Windows apps overview” ↩ ↩2
-
Microsoft Learn,“What’s new in WPF for .NET 9” ↩
-
Microsoft Learn,“What’s new in WinForms for .NET 9” ↩
-
Microsoft Learn,“Windows App SDK release channels” ↩
相关文章
共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。
委托开发 Windows 应用程序前该梳理的事项
在委托外包开发 Windows 应用程序之前,梳理现有软件改造、设备联动、COM/ActiveX、发布与更新、维护等需要注意的要点。
“无响应”的真相——Windows 如何判定应用卡死,以及不会卡死的设计
Windows 的“无响应”是操作系统在窗口 5 秒未取出消息时作出判定、并换成幽灵窗口的机制。本文讲解判定的内部动作、卡死的常见原因、把繁重处理移出 UI 线程的设计,以及挂起的调查步骤。
Windows 应用的任务栏托盘常驻与 Toast 通知 —— NotifyIcon 的坑与 AppNotification 的选型
本文整理了将业务 Windows 应用常驻在任务栏托盘(通知区域)并通过 Toast 通知告知用户的实现要点。内容涵盖 NotifyIcon 的正确用法与「关闭后驻留托盘」的设计、资源管理器重启后的重新注册、三种 Toast API(Windows App SDK AppN...
Windows 打印驱动程序停止提供 ── 业务应用的报表与标签打印如何应对
Microsoft 正在分阶段推进 v3/v4 打印驱动程序的停止提供,从 2026 年 7 月起会优先选择 IPP 类驱动程序。本文梳理 Windows protected print mode 下会消失什么,并用判断表整理业务应用程序的报表、标签打印中依赖点的盘点方法与...
剪贴板与拖放的工作原理——在业务应用中正确处理 OLE 数据传输
粘贴 Excel 表格会散架、关掉复制源就贴不上,根源都是剪贴板把同一内容放成多种格式的机制。本文讲解标准格式、延迟渲染、OLE 拖放,直到剪贴板历史与云同步的策略。
相关主题
与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。
Windows 技术主题
汇整 KomuraSoft LLC 关于 Windows 开发、故障调查与既有资产活用文章的主题中心。
UI 线程 & 计时器
整理 WPF / WinForms UI 线程、异步流程、Dispatcher 使用、计时器判断的主题页面。
与本主题相关的服务
本文与以下服务页面相关联,欢迎从最接近的入口查看。
Windows 应用程序开发
WinForms、WPF、WinUI 的选型,直接关系到 Windows 桌面应用的全新开发,以及存量资产的延续维护方针。
技术咨询 & 设计评审
适合在需要把存量资产、Windows App SDK、发布设计、UI 表现力、MVVM 文化都纳入考虑,梳理出哪个选择摩擦最小的阶段使用。
常见问题
汇总了咨询这一主题时常见的问题。
- 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。