【用途】 本技能面向将 WPF 应用程序迁移到 WinUI 3 的工作流,按步骤给出可执行的迁移方法与命令。使用前提是 WinApp CLI 0.7+ 及 winui-dev-workflow 中的应用分析器配置;常规 SDK 路径需要 .NET 8.0.100 或更高版本,以及目标 TFM 所需的 SDK;若使用 Native AOT,还需要 MSVC/Desktop C++ 工具。
【主要能力】
- 迁移前审计:用 PowerShell 的 Select-String 递归扫描 *.cs 文件(排除 obj 目录),查找 System.Windows. 的使用,并清点 WPF 控件、自定义 MVVM 框架、图像 API、线程模式和 Win32 互操作。
- 创建 WinUI 3 项目并统一命名空间:使用 winapp new --name <AppName> --template winui-mvvm --template-version latest --use-defaults 创建项目,随后在 .csproj 中设置 <RootNamespace> 与 WPF 命名空间一致,更新 App.xaml、MainWindow.xaml 及其代码隐藏文件中的 x:Class,并加入分析器后先构建验证。
- API 查询:在 WinUI 项目目录下用 winapp find-api 查询 API 与成员,例如 DispatcherQueue、DispatcherQueue 的 TryEnqueue、ListView 的 ItemsSource/SelectionMode;可用 winapp find-ui "<intent>" 获取用法示例。
- 命名空间替换映射: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 需完全移除。
- 控件替换映射:DataGrid → 带 Grid 列头的 ListView;WrapPanel → ItemsRepeater + UniformGridLayout;TabControl → TabView;StatusBar → 底部 Grid 行加 TextBlock;Menu / MenuItem → MenuBar / MenuBarItem / MenuFlyoutItem;ToolBar → CommandBar;自定义 Expander → 内置 Expander。
- 线程替换:WPF 的 Application.Current.Dispatcher.Invoke(() => { /* UI work / }); 改为 dispatcherQueue.TryEnqueue(() => { / UI work */ });,并通过 DispatcherQueue.GetForCurrentThread() 获取;WinUI 3 中没有 Application.Current.Dispatcher。
- 图像替换: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 步迁移。
- MVVM 框架替换:删除自定义 ObservableObject/RelayCommand/DelegateCommand,改用 CommunityToolkit.Mvvm;INotifyPropertyChanged 基类改为 ObservableObject 配合 [ObservableProperty] partial 属性(修复 MVVMTK0045,不要保留字段);自定义 RelayCommand 改为 [RelayCommand] 特性;已知类型优先使用 {x:Bind},必要时保留运行时 {Binding}/DisplayMemberPath;DynamicResource 改为 {ThemeResource}。
- 资源替换:.resx → .resw(复制并重命名到 Strings\en-us\);{x:Static} → 用于本地化字符串的 x:Uid;Properties.Resources.Key → ResourceLoader.GetString("Key")。
【关键规则】 不得引用 PresentationCore、PresentationFramework 或 System.Windows.Controls 程序集;不得添加 <UseWPF>true</UseWPF>;不得删除 Package.appxmanifest;不得覆盖 App.xaml / App.xaml.cs,应把 WPF 代码合并进 WinUI 3 样板;默认保持打包形式。启动应使用项目模式的 winapp run,而非直接运行 .exe;迁移应拆分为文件级任务,而非一次性重写。
【迁移后校验】 再次用 Select-String 检查是否残留 System.Windows. 引用(应无结果);用 Test-Path "Package.appxmanifest" 确认打包保留;执行 dotnet build .\MyApp.csproj -p:Platform=x64 构建;用 winapp run .\MyApp.csproj --detach --json 运行迁移后的应用。UI 验证可参考 winui-ui-testing,崩溃诊断可参考 winui-dev-workflow;若计划使用 AOT,还需通过工作流的 AOT 路径测试发布产物,上述运行即使 Release 也是 JIT。
【适用场景与限制】 适用于把既有 WPF 应用迁移到 WinUI 3 的项目。具体分析器安装细节、项目选择与批量 API 检查、绑定模式与 x:DataType、AOT 安全运行时绑定等,需参考 winui-dev-workflow、winui-design、winui-packaging 及 winui-ui-testing 等相关资料。其他未在资料中说明的事项暂未提供。