Files
PowerToys/.github/skills/wpf-to-winui3-migration/references/xaml-migration.md
moooyo 7051b8939b [Skills] Add WPF to WinUI 3 migration agent skill (#46462)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
With this skills, we can easily enable AI to complete most of the tasks
involved in migrating from WPF to WinUI3.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46464
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:40:33 +00:00

366 lines
11 KiB
Markdown

# XAML Migration Guide
Detailed reference for migrating XAML from WPF to WinUI 3, based on the ImageResizer migration.
## XML Namespace Declaration Changes
### Before (WPF)
```xml
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyApp"
xmlns:m="clr-namespace:ImageResizer.Models"
xmlns:p="clr-namespace:ImageResizer.Properties"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
x:Class="MyApp.MainWindow">
```
### After (WinUI 3)
```xml
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp"
xmlns:m="using:ImageResizer.Models"
xmlns:converters="using:ImageResizer.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="MyApp.MainWindow">
```
### Key Changes
| WPF Syntax | WinUI 3 Syntax | Notes |
|------------|---------------|-------|
| `clr-namespace:Foo` | `using:Foo` | CLR namespace mapping |
| `clr-namespace:Foo;assembly=Bar` | `using:Foo` | Assembly qualification not needed |
| `xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"` | **Remove entirely** | WPF-UI namespace no longer needed |
| `xmlns:p="clr-namespace:...Properties"` | **Remove** | No more `.resx` string bindings |
| `sys:String` (from mscorlib) | `x:String` | XAML intrinsic types |
| `sys:Int32` | `x:Int32` | XAML intrinsic types |
| `sys:Boolean` | `x:Boolean` | XAML intrinsic types |
| `sys:Double` | `x:Double` | XAML intrinsic types |
## Unsupported Markup Extensions
| WPF Markup Extension | WinUI 3 Alternative |
|----------------------|---------------------|
| `{DynamicResource Key}` | `{ThemeResource Key}` (theme-reactive) or `{StaticResource Key}` |
| `{x:Static Type.Member}` | `{x:Bind}` to a static property, or code-behind |
| `{x:Type local:MyType}` | Not supported; use code-behind |
| `{x:Array}` | Not supported; create collections in code-behind |
| `{x:Code}` | Not supported |
### DynamicResource → ThemeResource
```xml
<!-- WPF -->
<TextBlock Foreground="{DynamicResource MyBrush}" />
<!-- WinUI 3 -->
<TextBlock Foreground="{ThemeResource MyBrush}" />
```
`ThemeResource` automatically updates when the app theme changes (Light/Dark/HighContrast). For truly dynamic non-theme resources, set values in code-behind or use data binding.
### x:Static Resource Strings → x:Uid
This is the most pervasive XAML change. WPF used `{x:Static}` to bind to strongly-typed `.resx` resource strings. WinUI 3 uses `x:Uid` with `.resw` files.
**WPF:**
```xml
<Button Content="{x:Static p:Resources.Cancel}" />
<TextBlock Text="{x:Static p:Resources.Input_Header}" />
```
**WinUI 3:**
```xml
<Button x:Uid="Cancel" />
<TextBlock x:Uid="Input_Header" />
```
In `Strings/en-us/Resources.resw`:
```xml
<data name="Cancel.Content" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="Input_Header.Text" xml:space="preserve">
<value>Select a size</value>
</data>
```
The `x:Uid` suffix (`.Content`, `.Text`, `.Header`, `.PlaceholderText`, etc.) matches the target property name.
### DataType with x:Type → Remove
**WPF:**
```xml
<DataTemplate DataType="{x:Type m:ResizeSize}">
```
**WinUI 3:**
```xml
<DataTemplate x:DataType="m:ResizeSize">
```
## WPF-UI (Lepo) Controls Removal
If the module uses the `WPF-UI` library, replace all Lepo controls with native WinUI 3 equivalents.
### Window
```xml
<!-- WPF (WPF-UI) -->
<ui:FluentWindow
ExtendsContentIntoTitleBar="True"
WindowStartupLocation="CenterScreen">
<ui:TitleBar Title="Image Resizer" />
...
</ui:FluentWindow>
<!-- WinUI 3 (native) -->
<Window>
<!-- Title bar managed via code-behind: this.ExtendsContentIntoTitleBar = true; -->
...
</Window>
```
### App.xaml Resources
```xml
<!-- WPF (WPF-UI) -->
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
<!-- WinUI 3 (native) -->
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
```
### Common Control Replacements
```xml
<!-- WPF-UI NumberBox -->
<ui:NumberBox Value="{Binding Width}" />
<!-- WinUI 3 -->
<NumberBox Value="{x:Bind ViewModel.Width, Mode=TwoWay}" />
<!-- WPF-UI InfoBar -->
<ui:InfoBar Title="Warning" Message="..." IsOpen="True" Severity="Warning" />
<!-- WinUI 3 -->
<InfoBar Title="Warning" Message="..." IsOpen="True" Severity="Warning" />
<!-- WPF-UI ProgressRing -->
<ui:ProgressRing IsIndeterminate="True" />
<!-- WinUI 3 -->
<ProgressRing IsActive="True" />
<!-- WPF-UI SymbolIcon -->
<ui:SymbolIcon Symbol="Add" />
<!-- WinUI 3 -->
<SymbolIcon Symbol="Add" />
```
### Button Patterns
```xml
<!-- WPF -->
<Button IsDefault="True" Content="OK" />
<Button IsCancel="True" Content="Cancel" />
<!-- WinUI 3 (no IsDefault/IsCancel) -->
<Button Style="{StaticResource AccentButtonStyle}" Content="OK" />
<Button Content="Cancel" />
<!-- Handle Enter/Escape keys in code-behind if needed -->
```
## Style and Template Changes
### Triggers → VisualStateManager
WPF `Triggers`, `DataTriggers`, and `EventTriggers` are not supported.
**WPF:**
```xml
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightBlue"/>
</Trigger>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="Opacity" Value="0.5"/>
</DataTrigger>
</Style.Triggers>
</Style>
```
**WinUI 3:**
```xml
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="RootGrid.Background" Value="LightBlue"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
```
### No Binding in Setter.Value
```xml
<!-- WPF (works) -->
<Setter Property="Foreground" Value="{Binding TextColor}"/>
<!-- WinUI 3 (does NOT work — use StaticResource) -->
<Setter Property="Foreground" Value="{StaticResource TextColorBrush}"/>
```
### Visual State Name Changes
| WPF | WinUI 3 |
|-----|---------|
| `MouseOver` | `PointerOver` |
| `Disabled` | `Disabled` |
| `Pressed` | `Pressed` |
## Resource Dictionary Changes
### Window.Resources → Grid.Resources
WinUI 3 `Window` is NOT a `DependencyObject` — no `Window.Resources`, `DataContext`, or `VisualStateManager`.
```xml
<!-- WPF -->
<Window>
<Window.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Red"/>
</Window.Resources>
<Grid>...</Grid>
</Window>
<!-- WinUI 3 -->
<Window>
<Grid>
<Grid.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Red"/>
</Grid.Resources>
...
</Grid>
</Window>
```
### Theme Dictionaries
```xml
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="MyBrush" Color="#FF000000"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="MyBrush" Color="#FFFFFFFF"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="MyBrush" Color="{ThemeResource SystemColorWindowTextColor}"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
```
## URI Scheme Changes
| WPF | WinUI 3 |
|-----|---------|
| `pack://application:,,,/MyAssembly;component/image.png` | `ms-appx:///Assets/image.png` |
| `pack://application:,,,/image.png` | `ms-appx:///image.png` |
| Relative path `../image.png` | `ms-appx:///image.png` |
Assets directory convention: `Resources/``Assets/<Module>/`
## Data Binding Changes
### {Binding} vs {x:Bind}
Both are available. Prefer `{x:Bind}` for compile-time safety and performance.
| Feature | `{Binding}` | `{x:Bind}` |
|---------|------------|------------|
| Default mode | `OneWay` | **`OneTime`** (explicit `Mode=OneWay` required!) |
| Context | `DataContext` | Code-behind class |
| Resolution | Runtime | Compile-time |
| Performance | Reflection-based | Compiled |
| Function binding | No | Yes |
### WPF-Specific Binding Features to Remove
```xml
<!-- These WPF-only features must be removed or rewritten -->
<TextBox Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />
<!-- WinUI 3: UpdateSourceTrigger not needed; TextBox uses PropertyChanged by default -->
<TextBox Text="{x:Bind ViewModel.Value, Mode=TwoWay}" />
{Binding RelativeSource={RelativeSource Self}, ...}
<!-- WinUI 3: Use x:Bind which binds to the page itself, or use ElementName -->
<ItemsControl ItemsSource="{Binding}" />
<!-- WinUI 3: Must specify explicit path -->
<ItemsControl ItemsSource="{x:Bind ViewModel.Items}" />
```
## WPF-Only Window Properties to Remove
These properties exist on WPF `Window` but not WinUI 3:
```xml
<!-- Remove from XAML — handle in code-behind via AppWindow API -->
SizeToContent="Height"
WindowStartupLocation="CenterScreen"
ResizeMode="NoResize"
ExtendsContentIntoTitleBar="True" <!-- Set in code-behind -->
```
## XAML Control Property Changes
| WPF Property | WinUI 3 Property | Notes |
|-------------|-----------------|-------|
| `Focusable` | `IsTabStop` | Different name |
| `SnapsToDevicePixels` | Not available | WinUI handles pixel snapping internally |
| `UseLayoutRounding` | `UseLayoutRounding` | Same |
| `IsHitTestVisible` | `IsHitTestVisible` | Same |
| `TextBox.VerticalScrollBarVisibility` | `ScrollViewer.VerticalScrollBarVisibility` (attached) | Attached property |
## XAML Formatting (XamlStyler)
After migration, run XamlStyler to normalize formatting:
- Alphabetize xmlns declarations and element attributes
- Add UTF-8 BOM to all XAML files
- Normalize comment spacing: `<!-- text -->``<!-- text -->`
PowerToys command: `.\.pipelines\applyXamlStyling.ps1 -Main`