wpf-to-winui3-migration
- Repo stars 133,756
- License Complete terms in LICENSE.txt
- Author repo PowerToys
WPF to WinUI 3 Migration Skill
Migrate PowerToys modules from WPF (System.Windows.*) to WinUI 3 (Microsoft.UI.Xaml.* / Windows App SDK). Based on patterns validated in the ImageResizer module migration.
When to Use This Skill
- Migrate a PowerToys module from WPF to WinUI 3
- Convert WPF XAML files to WinUI 3 XAML
- Replace
System.Windowsnamespaces withMicrosoft.UI.Xaml - Migrate
Dispatcherusage toDispatcherQueue - Migrate custom
Observable/RelayCommandto CommunityToolkit.Mvvm source generators - Replace WPF-UI (Lepo) controls with native WinUI 3 controls
- Convert imaging code from
System.Windows.Media.ImagingtoWindows.Graphics.Imaging - Handle WPF
Windowvs WinUIWindowdifferences (sizing, positioning, SizeToContent) - Migrate resource files from
.resxto.reswwithResourceLoader - Fix installer/build pipeline issues after WinUI 3 migration
- Update project files, NuGet packages, and signing config
Prerequisites
- Visual Studio 2022 17.4+
- Windows App SDK NuGet package (
Microsoft.WindowsAppSDK) - .NET 8+ with
net8.0-windows10.0.19041.0TFM - Windows 10 1803+ (April 2018 Update or newer)
Migration Strategy
Recommended Order
- Project file — Update TFM, NuGet packages, set
<UseWinUI>true</UseWinUI> - Data models and business logic — No UI dependencies, migrate first
- MVVM framework — Replace custom Observable/RelayCommand with CommunityToolkit.Mvvm
- Resource strings — Migrate
.resx→.resw, introduceResourceLoaderInstance - Services and utilities — Replace
System.Windowstypes, async-ify imaging code - ViewModels — Update Dispatcher usage, binding patterns
- Views/Pages — Starting from leaf pages with fewest dependencies
- Main page / shell — Last, since it depends on everything
- App.xaml / startup code — Merge carefully (do NOT overwrite WinUI 3 boilerplate)
- Installer & build pipeline — Update WiX, signing, build events
- Tests — Adapt for WinUI 3 runtime, async patterns
Key Principles
- Do NOT overwrite
App.xaml/App.xaml.cs— WinUI 3 has different application lifecycle boilerplate. Merge your resources and initialization code into the generated WinUI 3 App class. - Do NOT create Exe→WinExe
ProjectReference— Extract shared code to a Library project. This causes phantom build artifacts. - Use
Lazy<T>for resource-dependent statics —ResourceLoaderis not available at class-load time in all contexts.
Quick Reference Tables
Namespace Mapping
| WPF | WinUI 3 |
|---|---|
System.Windows |
Microsoft.UI.Xaml |
System.Windows.Controls |
Microsoft.UI.Xaml.Controls |
System.Windows.Media |
Microsoft.UI.Xaml.Media |
System.Windows.Media.Imaging |
Microsoft.UI.Xaml.Media.Imaging (UI) / Windows.Graphics.Imaging (processing) |
System.Windows.Input |
Microsoft.UI.Xaml.Input |
System.Windows.Data |
Microsoft.UI.Xaml.Data |
System.Windows.Threading |
Microsoft.UI.Dispatching |
System.Windows.Interop |
WinRT.Interop |
Critical API Replacements
| WPF | WinUI 3 | Notes |
|---|---|---|
Dispatcher.Invoke() |
DispatcherQueue.TryEnqueue() |
Different return type (bool) |
Dispatcher.CheckAccess() |
DispatcherQueue.HasThreadAccess |
Property vs method |
Application.Current.Dispatcher |
Store DispatcherQueue in static field |
See Threading |
MessageBox.Show() |
ContentDialog |
Must set XamlRoot |
DynamicResource |
ThemeResource |
Theme-reactive only |
clr-namespace: |
using: |
XAML namespace prefix |
{x:Static props:Resources.Key} |
x:Uid or ResourceLoader.GetString() |
.resx → .resw |
DataType="{x:Type m:Foo}" |
Remove or use code-behind | x:Type not supported |
Properties.Resources.MyString |
ResourceLoaderInstance.ResourceLoader.GetString("MyString") |
Lazy-init pattern |
Application.Current.MainWindow |
Custom App.Window static property |
Must track manually |
SizeToContent="Height" |
Custom SizeToContent() via AppWindow.Resize() |
See Windowing |
MouseLeftButtonDown |
PointerPressed |
Mouse → Pointer events |
Pack URI (pack://...) |
ms-appx:/// |
Resource URI scheme |
Observable (custom base) |
ObservableObject + [ObservableProperty] |
CommunityToolkit.Mvvm |
RelayCommand (custom) |
[RelayCommand] source generator |
CommunityToolkit.Mvvm |
JpegBitmapEncoder |
BitmapEncoder.CreateAsync(JpegEncoderId, stream) |
Async, unified API |
encoder.QualityLevel = 85 |
BitmapPropertySet { "ImageQuality", 0.85f } |
int 1-100 → float 0-1 |
NuGet Package Migration
| WPF | WinUI 3 |
|---|---|
Microsoft.Xaml.Behaviors.Wpf |
Microsoft.Xaml.Behaviors.WinUI.Managed |
WPF-UI (Lepo) |
Remove — use native WinUI 3 controls |
CommunityToolkit.Mvvm |
CommunityToolkit.Mvvm (same) |
Microsoft.Toolkit.Wpf.* |
CommunityToolkit.WinUI.* |
| (none) | Microsoft.WindowsAppSDK |
| (none) | Microsoft.Windows.SDK.BuildTools |
| (none) | WinUIEx (optional, for window helpers) |
| (none) | CommunityToolkit.WinUI.Converters |
XAML Syntax Changes
| WPF | WinUI 3 |
|---|---|
xmlns:local="clr-namespace:MyApp" |
xmlns:local="using:MyApp" |
{DynamicResource Key} |
{ThemeResource Key} |
{x:Static Type.Member} |
{x:Bind} or code-behind |
{x:Type local:MyType} |
Not supported |
<Style.Triggers> / <DataTrigger> |
VisualStateManager |
{Binding} in Setter.Value |
Not supported — use StaticResource |
Content="{x:Static p:Resources.Cancel}" |
x:Uid="Cancel" with .Content in .resw |
<ui:FluentWindow> / <ui:Button> (WPF-UI) |
Native <Window> / <Button> |
<ui:NumberBox> / <ui:ProgressRing> (WPF-UI) |
Native <NumberBox> / <ProgressRing> |
BasedOn="{StaticResource {x:Type ui:Button}}" |
BasedOn="{StaticResource DefaultButtonStyle}" |
IsDefault="True" / IsCancel="True" |
Style="{StaticResource AccentButtonStyle}" / handle via KeyDown |
<AccessText> |
Not available — use AccessKey property |
<behaviors:Interaction.Triggers> |
Migrate to code-behind or WinUI behaviors |
Detailed Reference Docs
Read only the section relevant to your current task:
- Namespace and API Mapping — Full type mapping, NuGet changes, project file, CsWinRT interop
- XAML Migration Guide — XAML syntax, WPF-UI removal, markup extensions, styles, resources, data binding
- Threading and Window Management — Dispatcher, DispatcherQueue, SizeToContent, AppWindow, HWND interop, custom entry point
- Imaging API Migration — BitmapEncoder/Decoder, SoftwareBitmap, CodecHelper, async patterns, int→uint
- PowerToys-Specific Patterns — MVVM migration, ResourceLoader, Lazy init, installer, signing, test adaptation, build pipeline
Common Pitfalls (from ImageResizer migration)
| Pitfall | Solution |
|---|---|
ContentDialog throws "does not have a XamlRoot" |
Set dialog.XamlRoot = this.Content.XamlRoot before ShowAsync() |
FilePicker throws error in desktop app |
Call WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd) |
Window.Dispatcher returns null |
Use Window.DispatcherQueue instead |
Resources on Window element not found |
Move resources to root layout container (Grid.Resources) |
VisualStateManager on Window fails |
Use UserControl or Page inside the Window |
Satellite assembly installer errors (WIX0103) |
Remove .resources.dll refs from Resources.wxs; WinUI 3 uses .pri |
Phantom .exe/.deps.json in root output dir |
Avoid Exe→WinExe ProjectReference; use Library project |
ResourceLoader crash at static init |
Wrap in Lazy<T> or null-coalescing property — see Lazy Init |
SizeToContent not available |
Implement manual content measurement + AppWindow.Resize() with DPI scaling |
x:Bind default mode is OneTime |
Explicitly set Mode=OneWay or Mode=TwoWay |
DynamicResource / x:Static not compiling |
Replace with ThemeResource / ResourceLoader or x:Uid |
IValueConverter.Convert signature mismatch |
Last param: CultureInfo → string (language tag) |
| Test project can't resolve WPF types | Add <UseWPF>true</UseWPF> temporarily; remove after imaging migration |
Pixel dimension type mismatch (int vs uint) |
WinRT uses uint for pixel sizes — add u suffix in test assertions |
$(SolutionDir) empty in standalone project build |
Use $(MSBuildThisFileDirectory) with relative paths instead |
| JPEG quality value wrong after migration | WPF: int 1-100; WinRT: float 0.0-1.0 |
| MSIX packaging fails in PreBuildEvent | Move to PostBuildEvent; artifacts not ready at PreBuild time |
| RC file icon path with forward slashes | Use double-backslash escaping: ..\\ui\\Assets\\icon.ico |
Troubleshooting
| Issue | Solution |
|---|---|
| Build fails after namespace rename | Check for lingering System.Windows usings; some types have no direct equivalent |
Missing PresentationCore.dll at runtime |
Ensure ALL imaging code uses Windows.Graphics.Imaging, not System.Windows.Media.Imaging |
DataContext not working on Window |
WinUI 3 Window is not a DependencyObject; use a root Page or UserControl |
| XAML designer not available | WinUI 3 does not support XAML Designer; use Hot Reload instead |
| NuGet restore failures | Run build-essentials.cmd after adding Microsoft.WindowsAppSDK package |
Parallel.ForEach compilation error |
Migrate to Parallel.ForEachAsync for async imaging operations |
| Signing check fails on leaked artifacts | Run generateAllFileComponents.ps1; verify only WinUI3Apps\\ paths in signing config |
- Fluxly category
- Engineering
- Author-declared agents
- No explicit declaration found; this is not inferred or tested compatibility
- Static check
- 94 / 100 · heuristic scan, not runtime safety proof
- Author / version / license
- @microsoft · Complete terms in LICENSE.txt
- Fluxly token estimate
- Lean
- Fluxly setup estimate
- Guided setup
- External API key
- No requirement detected
- Detected OS requirements
- Windows
- Runtime requirements
- Unspecified
- Detected file/system behavior
-
- Read-only
- Write / modify
- Shell exec
- Detected network behavior
- Local-only
- Install commands
- None (reference only)
Profile is derived at build time from SKILL.md and install vectors. Subject to drift from author intent.
Heads up: 未限定 allowed-tools,默认拥有全部工具权限。
The current SKILL.md does not define a fixed output example. Migrate a PowerToys module from WPF to WinUI 3 Convert WPF XAML files to WinUI 3 XAML Replace System.Windows namespaces with Microsoft.UI.Xaml
Visual Studio 2022 17.4+ Windows App SDK NuGet package (Microsoft.WindowsAppSDK) .NET 8+ with net8.0-windows10.0.19041.0 TFM
Migration Strategy
Project file — Update TFM, NuGet packages, set <UseWinUI>true</UseWinUI> Data models and business logic — No UI dependencies, migrate first MVVM framework — Replace custom Observable/RelayCommand with CommunityToolkit.Mvvm
Do NOT overwrite App.xaml / App.xaml.cs — WinUI 3 has different application lifecycle boilerplate. Merge your resources and initialization code into the generated WinUI 3 App class. Do NOT create Exe→WinExe ProjectReference — Extract shared code to a Library…
Quick Reference Tables
# WPF to WinUI 3 Migration Skill
Migrate PowerToys modules from WPF (`System.Windows.*`) to WinUI 3 (`Microsoft.UI.Xaml.*` / Windows App SDK). Based on patterns validated in the ImageResizer module migration.
## When to Use This Skill
- Migrate a PowerToys module from WPF to WinUI 3
- Convert WPF XAML files to WinUI 3 XAML
- Replace `System.Windows` namespaces with `Microsoft.UI.Xaml`
- Migrate `Dispatcher` usage to `DispatcherQueue`
- Migrate custom `Observable`/`RelayCommand` to CommunityToolkit.Mvvm source generators
- Replace WPF-UI (Lepo) controls with native WinUI 3 controls
- Convert imaging code from `System.Windows.Media.Imaging` to `Windows.Graphics.Imaging`
- Handle WPF `Window` vs WinUI `Window` differences (sizing, positioning, SizeToContent)
- Migrate resource files from `.resx` to `.resw` with `ResourceLoader`
- Fix installer/build pipeline issues after WinUI 3 migration
- Update project files, NuGet packages, and signing config
## Prerequisites
- Visual Studio 2022 17.4+
- Windows App SDK NuGet package (`Microsoft.WindowsAppSDK`)
- .NET 8+ with `net8.0-windows10.0.19041.0` TFM
- Windows 10 1803+ (April 2018 Update or newer)
## Migration Strategy
### Recommended Order
1. **Project file** — Update TFM, NuGet packages, set `<UseWinUI>true</UseWinUI>`
2. **Data models and business logic** — No UI dependencies, migrate first
3. **MVVM framework** — Replace custom Observable/RelayCommand with CommunityToolkit.Mvvm
4. **Resource strings** — Migrate `.resx` → `.resw`, introduce `ResourceLoaderInstance`
5. **Services and utilities** — Replace `System.Windows` types, async-ify imaging code
6. **ViewModels** — Update Dispatcher usage, binding patterns
7. **Views/Pages** — Starting from leaf pages with fewest dependencies
… Author text anchors workflow facts; Fluxly only indexes current sections, terms, files, and commands.
sections -> When to Use This Skill → Prerequisites → Migration Strategy → Recommended Order → Key Principles → Quick Reference Tables
terms -> Project file · Data models and business logic · MVVM framework · Resource strings · Services and utilities · ViewModels · Views/Pages · Main page / shell
files/cmd -> System.Windows. · Microsoft.UI.Xaml. · System.Windows · Microsoft.UI.Xaml · Dispatcher · DispatcherQueue · Observable · RelayCommand
body sha256 -> 90b8232fd1f3
Decide Fit First
Design Intent
How To Use It
Boundaries And Review