winui-wpf-migration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMigration Process
迁移流程
Step 1: Audit the WPF Source
步骤1:审计WPF源代码
Before writing code, inventory WPF-specific APIs:
powershell
undefined在编写代码前,清点WPF专属API:
powershell
undefinedFind all WPF namespace usage
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
List: WPF controls used, custom MVVM framework, imaging APIs, threading patterns, Win32 interop.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互操作。Step 2: Create WinUI 3 Project and Align Namespaces
步骤2:创建WinUI 3项目并对齐命名空间
powershell
dotnet new winui-mvvm -n <AppName>Immediately set in to match the WPF namespace. Update in , and their code-behind files. Build to verify before porting any code.
<RootNamespace>.csprojx:ClassApp.xamlMainWindow.xamlpowershell
dotnet new winui-mvvm -n <AppName>立即在中设置以匹配WPF命名空间。更新、及其代码隐藏文件中的。在移植任何代码前先构建以验证正确性。
.csproj<RootNamespace>App.xamlMainWindow.xamlx:ClassStep 3: Replace Namespaces
步骤3:替换命名空间
| WPF | WinUI 3 |
|---|---|
| |
| |
| |
| |
| |
| |
| Remove entirely |
| WPF | WinUI 3 |
|---|---|
| |
| |
| |
| |
| |
| |
| 完全移除 |
Step 4: Replace Controls
步骤4:替换控件
| WPF Control | WinUI 3 Equivalent |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| WPF控件 | WinUI 3等效控件 |
|---|---|
| 带网格列头的 |
| |
| |
| 底部包含 |
| |
| |
| |
Step 5: Replace Threading
步骤5:替换线程处理逻辑
csharp
// WPF
Application.Current.Dispatcher.Invoke(() => { /* UI work */ });
// WinUI 3
dispatcherQueue.TryEnqueue(() => { /* UI work */ });Get via . No in WinUI 3.
DispatcherQueue.GetForCurrentThread()Application.Current.Dispatchercsharp
// WPF
Application.Current.Dispatcher.Invoke(() => { /* UI work */ });
// WinUI 3
dispatcherQueue.TryEnqueue(() => { /* UI work */ });通过获取DispatcherQueue。WinUI 3中没有。
DispatcherQueue.GetForCurrentThread()Application.Current.DispatcherStep 6: Replace Imaging
步骤6:替换图像处理方案
Critical: and crash the WinUI XAML compiler. This is an architectural incompatibility — no workaround exists.
PresentationCore.dllSystem.Windows.Media.Imaging- Remove ALL references at migration start
System.Windows.Media.Imaging - Replace with (WinRT) or
Windows.Graphics.ImagingMicrosoft.UI.Xaml.Media.Imaging.BitmapImage - Do NOT add — it silently corrupts the build
<UseWPF>true</UseWPF> - If heavy imaging code exists, migrate it early (step 2, not step 7)
关键注意事项: 和会导致WinUI XAML编译器崩溃。这是架构不兼容问题——没有解决办法。
PresentationCore.dllSystem.Windows.Media.Imaging- 迁移开始时移除所有引用
System.Windows.Media.Imaging - 使用(WinRT)或
Windows.Graphics.Imaging替代Microsoft.UI.Xaml.Media.Imaging.BitmapImage - 切勿添加——它会静默破坏构建
<UseWPF>true</UseWPF> - 如果存在大量图像处理代码,请尽早迁移(步骤2而非步骤7)
Step 7: Replace MVVM Framework
步骤7:替换MVVM框架
Delete custom //. Use CommunityToolkit.Mvvm:
ObservableObjectRelayCommandDelegateCommand- base →
INotifyPropertyChangedwithObservableObjectpartial properties[ObservableProperty] - Custom →
RelayCommandattribute[RelayCommand] - →
{Binding}{x:Bind Mode=OneWay} - →
DynamicResource{ThemeResource}
删除自定义的//。使用CommunityToolkit.Mvvm:
ObservableObjectRelayCommandDelegateCommand- 基类 → 带有
INotifyPropertyChanged分部属性的[ObservableProperty]ObservableObject - 自定义→
RelayCommand特性[RelayCommand] - →
{Binding}{x:Bind Mode=OneWay} - →
DynamicResource{ThemeResource}
Step 8: Replace Resources
步骤8:替换资源
- →
.resx(copy + rename to.resw)Strings\en-us\ - →
{x:Static}for localized stringsx:Uid - →
Properties.Resources.KeyResourceLoader.GetString("Key")
- →
.resx(复制并重命名至.resw目录)Strings\en-us\ - → 使用
{x:Static}处理本地化字符串x:Uid - →
Properties.Resources.KeyResourceLoader.GetString("Key")
Critical Rules
关键规则
- ❌ NEVER reference ,
PresentationCore, orPresentationFrameworkassembliesSystem.Windows.Controls - ❌ NEVER add or
<UseWPF>true</UseWPF><WindowsPackageType>None</WindowsPackageType> - ❌ NEVER delete
Package.appxmanifest - ❌ NEVER overwrite /
App.xaml— merge WPF code into the WinUI 3 boilerplateApp.xaml.cs - ✅ Always use to launch — never run the .exe directly
winapp run - ✅ Break migration into file-level tasks — not one massive rewrite
- ❌ 绝对不要引用、
PresentationCore或PresentationFramework程序集System.Windows.Controls - ❌ 绝对不要添加或
<UseWPF>true</UseWPF><WindowsPackageType>None</WindowsPackageType> - ❌ 绝对不要删除
Package.appxmanifest - ❌ 绝对不要覆盖/
App.xaml——将WPF代码合并到WinUI 3的模板代码中App.xaml.cs - ✅ 始终使用启动应用——切勿直接运行.exe文件
winapp run - ✅ 将迁移拆分为按文件处理的任务——不要一次性大规模重写
Post-Migration Validation
迁移后验证
powershell
undefinedpowershell
undefinedCheck for remaining WPF references (should return nothing)
Check for remaining WPF references (should return nothing)
Select-String -Path (Get-ChildItem -Recurse -Filter ".cs" | Where-Object { $_.FullName -notlike "\obj*" }) -Pattern "System.Windows."
Select-String -Path (Get-ChildItem -Recurse -Filter ".cs" | Where-Object { $_.FullName -notlike "\obj*" }) -Pattern "System.Windows."
Verify packaging preserved
Verify packaging preserved
Test-Path "Package.appxmanifest" # should be True
Test-Path "Package.appxmanifest" # should be True
Build and run
Build and run
.\BuildAndRun.ps1
undefined.\BuildAndRun.ps1
undefined