关于 winui-wpf-migration
winui-wpf-migration 是指导将 WPF 应用迁移到 WinUI 3 的技能,面向执行 Windows 桌面应用迁移的开发者。内容按迁移步骤覆盖 API、控件、线程、图像处理和 MVVM 替换,并包含迁移后验证。
主要功能
- 01盘点 WPF 专用 API
- 02指导 WinUI 3 项目初始化
- 03映射命名空间与控件
- 04迁移线程和图像处理
- 05替换 MVVM 与资源
- 06提供迁移后验证步骤
适用场景
- 01制定 WPF 应用迁移计划
- 02替换不兼容的 WPF API
- 03逐步迁移控件和 MVVM 代码
- 04检查迁移后的构建与打包
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ win-dev-skills --skill winui-wpf-migration安装后在 Claude Code 中输入/winui-wpf-migration确认已加载。
详细介绍
迁移流程
使用 winui-dev-workflow 中的 WinApp CLI 0.7+ 前置条件和针对每个应用的分析器设置。常规 SDK 路径需要 .NET 8.0.100 或更高版本,以及目标 TFM 所需的 SDK;Native AOT 还需要 MSVC/Desktop C++ 工具。按照该文档中的说明处理缺失的前置条件。
步骤 1:审查 WPF 源代码
编写代码前,先盘点 WPF 专用 API:
# Find all WPF namespace usage
Select-String -Path (Get-ChildItem -Recurse -Filter "*.cs" | Where-Object { $_.FullName -notlike "*\obj\*" }) -Pattern "System\.Windows\." | Select-Object -Property Filename, LineNumber, Line
清单:使用的 WPF 控件、自定义 MVVM 框架、成像 API、线程处理模式、Win32 互操作。
步骤 2:创建 WinUI 3 项目并对齐命名空间
winapp new --name <AppName> --template winui-mvvm --template-version latest --use-defaults
立即在 .csproj 中设置 <RootNamespace>,使其与 WPF 命名空间一致。更新 App.xaml、MainWindow.xaml 及其代码隐藏文件中的 x:Class。按照 winui-dev-workflow 添加分析器。在移植任何代码前先构建验证。
实现 API 替换前,在 WinUI 项目目录中还原应用项目,并检查其实际引用;不要从旧 WPF 项目或计算机 SDK 检查:
winapp find-api DispatcherQueue --json --project-dir .
winapp find-api members DispatcherQueue --filter TryEnqueue --json --project-dir .
winapp find-api check-property ListView ItemsSource SelectionMode --json --project-dir .
使用 winapp find-ui "<intent>" 获取用法示例;项目选择和批量 API 检查请参阅 winui-design。
步骤 3:替换命名空间
| WPF | WinUI 3 |
|---|---|
System.Windows | Microsoft.UI.Xaml |
System.Windows.Controls | Microsoft.UI.Xaml.Controls |
System.Windows.Media | Microsoft.UI.Xaml.Media |
System.Windows.Input | Microsoft.UI.Xaml.Input |
System.Windows.Data | Microsoft.UI.Xaml.Data |
System.Windows.Threading.Dispatcher | Microsoft.UI.Dispatching.DispatcherQueue |
PresentationCore / PresentationFramework | 完全移除 |
步骤 4:替换控件
| WPF 控件 | WinUI 3 对应项 |
|---|---|
DataGrid | 带 Grid 列标题的 ListView |
WrapPanel | ItemsRepeater + UniformGridLayout |
TabControl | TabView |
StatusBar | 底部带 TextBlock 元素的 Grid 行 |
Menu / MenuItem | MenuBar / MenuBarItem / MenuFlyoutItem |
ToolBar | CommandBar |
Expander(自定义) | Expander(内置) |
步骤 5:替换线程处理
// WPF
Application.Current.Dispatcher.Invoke(() => { /* UI work */ });
// WinUI 3
dispatcherQueue.TryEnqueue(() => { /* UI work */ });
通过 DispatcherQueue.GetForCurrentThread() 获取。WinUI 3 中没有 Application.Current.Dispatcher。
步骤 6:替换成像功能
重要: PresentationCore.dll 和 System.Windows.Media.Imaging 会导致 WinUI XAML 编译器崩溃。这是架构不兼容,无法规避。
- 在迁移开始时移除所有
System.Windows.Media.Imaging引用 - 替换为
Windows.Graphics.Imaging(WinRT)或Microsoft.UI.Xaml.Media.Imaging.BitmapImage - 不要添加
<UseWPF>true</UseWPF>—— 这会悄悄破坏构建 - 如果存在大量成像代码,请尽早迁移(第 2 步,而不是第 7 步)
步骤 7:替换 MVVM 框架
删除自定义的 ObservableObject/RelayCommand/DelegateCommand。使用 CommunityToolkit.Mvvm:
INotifyPropertyChanged基类 → 使用[ObservableProperty]partial 属性的ObservableObject(修复 MVVMTK0045;不要保留字段)- 自定义
RelayCommand→[RelayCommand]特性 - 已知类型优先使用
{x:Bind};必要时保留运行时{Binding}/DisplayMemberPath。有关绑定模式、x:DataType和适用于 AOT 的运行时绑定,请参阅winui-packaging的references/sourcegen-patterns.md。 DynamicResource→{ThemeResource}
步骤 8:替换资源
.resx→.resw(复制并重命名到Strings\en-us\)- 本地化字符串使用
x:Uid替换{x:Static} Properties.Resources.Key→ResourceLoader.GetString("Key")
关键规则
- ❌ 绝不引用
PresentationCore、PresentationFramework或System.Windows.Controls程序集 - ❌ 绝不添加
<UseWPF>true</UseWPF> - 默认保持打包模式;若要进行非打包实验,请参阅
winui-dev-workflow的关键规则。 - ❌ 绝不删除
Package.appxmanifest - ❌ 绝不覆盖
App.xaml/App.xaml.cs——将 WPF 代码合并到 WinUI 3 样板代码中 - ✅ 使用项目模式的
winapp run启动,不要直接运行 .exe。 - ✅ 将迁移拆分为按文件执行的任务——不要一次性大规模重写
迁移后验证
# Check for remaining WPF references (should return nothing)
Select-String -Path (Get-ChildItem -Recurse -Filter "*.cs" | Where-Object { $_.FullName -notlike "*\obj\*" }) -Pattern "System\.Windows\."
# Verify packaging preserved
Test-Path "Package.appxmanifest" # should be True
# Build (the analyzer participates when installed)
dotnet build .\MyApp.csproj -p:Platform=x64
# Run the migrated app
winapp run .\MyApp.csproj --detach --json
UI 验证请参阅 winui-ui-testing;崩溃诊断请参阅 winui-dev-workflow。如果计划使用 AOT,还要通过工作流的 AOT 路径测试发布产物;上面的运行使用的是 JIT,即使在 Release 模式下也是如此。