winui-wpf-migration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Migration Process

迁移流程

Step 1: Audit the WPF Source

步骤1:审计WPF源代码

Before writing code, inventory WPF-specific APIs:
powershell
undefined
在编写代码前,清点WPF专属API:
powershell
undefined

Find 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
<RootNamespace>
in
.csproj
to match the WPF namespace. Update
x:Class
in
App.xaml
,
MainWindow.xaml
and their code-behind files. Build to verify before porting any code.
powershell
dotnet new winui-mvvm -n <AppName>
立即在
.csproj
中设置
<RootNamespace>
以匹配WPF命名空间。更新
App.xaml
MainWindow.xaml
及其代码隐藏文件中的
x:Class
。在移植任何代码前先构建以验证正确性。

Step 3: Replace Namespaces

步骤3:替换命名空间

WPFWinUI 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
Remove entirely
WPFWinUI 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
完全移除

Step 4: Replace Controls

步骤4:替换控件

WPF ControlWinUI 3 Equivalent
DataGrid
ListView
with Grid column headers
WrapPanel
ItemsRepeater
+
UniformGridLayout
TabControl
TabView
StatusBar
Grid
row at bottom with
TextBlock
elements
Menu
/
MenuItem
MenuBar
/
MenuBarItem
/
MenuFlyoutItem
ToolBar
CommandBar
Expander
(custom)
Expander
(built-in)
WPF控件WinUI 3等效控件
DataGrid
带网格列头的
ListView
WrapPanel
ItemsRepeater
+
UniformGridLayout
TabControl
TabView
StatusBar
底部包含
TextBlock
元素的
Grid
Menu
/
MenuItem
MenuBar
/
MenuBarItem
/
MenuFlyoutItem
ToolBar
CommandBar
Expander
(自定义)
Expander
(内置)

Step 5: Replace Threading

步骤5:替换线程处理逻辑

csharp
// WPF
Application.Current.Dispatcher.Invoke(() => { /* UI work */ });

// WinUI 3
dispatcherQueue.TryEnqueue(() => { /* UI work */ });
Get via
DispatcherQueue.GetForCurrentThread()
. No
Application.Current.Dispatcher
in WinUI 3.
csharp
// WPF
Application.Current.Dispatcher.Invoke(() => { /* UI work */ });

// WinUI 3
dispatcherQueue.TryEnqueue(() => { /* UI work */ });
通过
DispatcherQueue.GetForCurrentThread()
获取DispatcherQueue。WinUI 3中没有
Application.Current.Dispatcher

Step 6: Replace Imaging

步骤6:替换图像处理方案

Critical:
PresentationCore.dll
and
System.Windows.Media.Imaging
crash the WinUI XAML compiler. This is an architectural incompatibility — no workaround exists.
  • Remove ALL
    System.Windows.Media.Imaging
    references at migration start
  • Replace with
    Windows.Graphics.Imaging
    (WinRT) or
    Microsoft.UI.Xaml.Media.Imaging.BitmapImage
  • Do NOT add
    <UseWPF>true</UseWPF>
    — it silently corrupts the build
  • If heavy imaging code exists, migrate it early (step 2, not step 7)
关键注意事项:
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)

Step 7: Replace MVVM Framework

步骤7:替换MVVM框架

Delete custom
ObservableObject
/
RelayCommand
/
DelegateCommand
. Use CommunityToolkit.Mvvm:
  • INotifyPropertyChanged
    base →
    ObservableObject
    with
    [ObservableProperty]
    partial properties
  • Custom
    RelayCommand
    [RelayCommand]
    attribute
  • {Binding}
    {x:Bind Mode=OneWay}
  • DynamicResource
    {ThemeResource}
删除自定义的
ObservableObject
/
RelayCommand
/
DelegateCommand
。使用CommunityToolkit.Mvvm:
  • INotifyPropertyChanged
    基类 → 带有
    [ObservableProperty]
    分部属性的
    ObservableObject
  • 自定义
    RelayCommand
    [RelayCommand]
    特性
  • {Binding}
    {x:Bind Mode=OneWay}
  • DynamicResource
    {ThemeResource}

Step 8: Replace Resources

步骤8:替换资源

  • .resx
    .resw
    (copy + rename to
    Strings\en-us\
    )
  • {x:Static}
    x:Uid
    for localized strings
  • Properties.Resources.Key
    ResourceLoader.GetString("Key")
  • .resx
    .resw
    (复制并重命名至
    Strings\en-us\
    目录)
  • {x:Static}
    → 使用
    x:Uid
    处理本地化字符串
  • Properties.Resources.Key
    ResourceLoader.GetString("Key")

Critical Rules

关键规则

  • ❌ NEVER reference
    PresentationCore
    ,
    PresentationFramework
    , or
    System.Windows.Controls
    assemblies
  • ❌ NEVER add
    <UseWPF>true</UseWPF>
    or
    <WindowsPackageType>None</WindowsPackageType>
  • ❌ NEVER delete
    Package.appxmanifest
  • ❌ NEVER overwrite
    App.xaml
    /
    App.xaml.cs
    — merge WPF code into the WinUI 3 boilerplate
  • ✅ Always use
    winapp run
    to launch — never run the .exe directly
  • ✅ 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
    /
    App.xaml.cs
    ——将WPF代码合并到WinUI 3的模板代码中
  • ✅ 始终使用
    winapp run
    启动应用——切勿直接运行.exe文件
  • ✅ 将迁移拆分为按文件处理的任务——不要一次性大规模重写

Post-Migration Validation

迁移后验证

powershell
undefined
powershell
undefined

Check 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