- WPF's
System.Windows.*namespaces map toMicrosoft.UI.Xaml.*in WinUI, but not every class has a 1:1 equivalent - Most core layout and input controls transfer with minimal changes
- Several WPF controls (
DataGrid,Ribbon,StatusBar) require Community Toolkit, community projects, or alternative controls - WPF patterns like DataTriggers, MultiBinding, Adorners, and DynamicResource have no direct WinUI equivalent
Visibility.HiddenandFocusablerequire multiple WinUI properties set together to preserve behavior- Uno Platform 6.5 on .NET 10 implements the WinUI 3 API surface across all targets
- Includes a ready-to-use AI prompt template for automated XAML translation
Who this is for: WPF developers actively migrating production code to WinUI 3 and Uno Platform. You should already understand WPF XAML fundamentals and have a migration project underway or planned.
If you are migrating a WPF application to WinUI and Uno Platform, this is the reference you keep open in a second monitor. It covers every major namespace change, control mapping, property translation, and pattern replacement you will encounter.
Bookmark this page. You will come back to it dozens of times during your migration.
Namespace Mapping Table
The single biggest mechanical change in any WPF-to-WinUI migration is swapping namespaces. Every System.Windows reference in your code-behind becomes a Microsoft.UI.Xaml reference.
| WPF Namespace | WinUI 3 Namespace | Notes |
|---|---|---|
System.Windows | Microsoft.UI.Xaml | Root namespace |
System.Windows.Controls | Microsoft.UI.Xaml.Controls | Core controls |
System.Windows.Controls.Primitives | Microsoft.UI.Xaml.Controls.Primitives | Low-level primitives |
System.Windows.Media | Microsoft.UI.Xaml.Media | Brushes, transforms |
System.Windows.Media.Animation | Microsoft.UI.Xaml.Media.Animation | Storyboard, animations |
System.Windows.Media.Imaging | Microsoft.UI.Xaml.Media.Imaging | BitmapImage, WriteableBitmap |
System.Windows.Media.Media3D | No equivalent | Use Win2D or Composition APIs |
System.Windows.Shapes | Microsoft.UI.Xaml.Shapes | Rectangle, Ellipse, Path |
System.Windows.Data | Microsoft.UI.Xaml.Data | Binding, IValueConverter |
System.Windows.Input | Microsoft.UI.Xaml.Input | Pointer, keyboard, focus |
System.Windows.Navigation | No direct equivalent | Use Frame.Navigate() |
System.Windows.Documents | No direct equivalent | Limited via RichTextBlock |
System.Windows.Markup | Microsoft.UI.Xaml.Markup | XAML parsing |
System.Windows.Automation | Microsoft.UI.Xaml.Automation | Accessibility |
System.Windows.Interop | Microsoft.UI.Xaml.Hosting | XAML Islands, etc. |
System.Windows.Threading | Microsoft.UI.Dispatching | Dispatcher becomes DispatcherQueue |
XAML Namespace Declarations
The default XML namespace URI is the same in both WPF and WinUI, but the underlying types it resolves to are different. Your XAML files may compile without namespace changes, but your code-behind requires a full using statement update.
| WPF | WinUI |
|---|---|
xmlns:local="clr-namespace:MyApp" | xmlns:local="using:MyApp" |
clr-namespace:MyApp;assembly=MyLib | using:MyApp (assembly inferred) |
Code-Behind Transformation
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Dispatching;Common Using Pitfalls
| WPF Code | WinUI Replacement | Why It Breaks |
|---|---|---|
Application.Current.Dispatcher | A captured DispatcherQueue (see Dispatcher section) | Dispatcher does not exist; use DispatcherQueue.TryEnqueue() |
Window.Current | Your own MainWindow property on App | Window.Current not supported in Windows App SDK |
Clipboard in System.Windows | Windows.ApplicationModel.DataTransfer.Clipboard | Different API surface entirely |
MessageBox.Show() | ContentDialog with XamlRoot set | No MessageBox in WinUI |
WinUI 3 does not expose a built-in App.MainWindow property. The convention is to create the window in App.OnLaunched, store it in a field, and expose it as a public static property (for example App.MainWindow) so other code can reach it. References to App.MainWindow elsewhere in this article follow that convention.
Controls That Map 1:1
Most everyday controls exist in WinUI with the same name and nearly identical behavior: Button, TextBox, TextBlock, ComboBox, ListBox, ListView, StackPanel, Grid, Border, Image, CheckBox, RadioButton, Slider, ProgressBar, ProgressRing, ScrollViewer, Canvas, ContentPresenter, ContentControl, ItemsControl, Popup, ToolTip, PasswordBox, DatePicker.
WinUI-Only Additions Worth Adopting
These have no direct WPF equivalent but are worth introducing during modernization: NavigationView, NumberBox, InfoBar, ToggleSwitch, HyperlinkButton, Expander, TeachingTip, ContentDialog, Flyout, RichEditBox, CalendarView, TimePicker, MediaPlayerElement.
Key Property Differences
| WPF Property / Value | WinUI Equivalent | Context |
|---|---|---|
Visibility.Hidden | Not available | Set Opacity="0" + IsHitTestVisible="False". Using Opacity="0" alone leaves the element clickable. |
TextWrapping.WrapWithOverflow | TextWrapping.Wrap | WinUI does not distinguish |
MouseLeftButtonDown | PointerPressed | Pointer model replaces mouse model |
MouseEnter / MouseLeave | PointerEntered / PointerExited | Pointer model |
PreviewMouseDown | PointerPressed (no tunneling) | Use AddHandler(..., handledEventsToo: true) |
Focusable | IsTabStop (and optionally AllowFocusOnInteraction) | IsTabStop="False" excludes from tab nav and blocks Focus() calls. Add AllowFocusOnInteraction="False" only when you also need to suppress pointer-interaction focus. |
Controls That Need Translation
| WPF Control | WinUI / Uno Replacement | Migration Notes |
|---|---|---|
DataGrid | Community Toolkit DataGrid (7.x) or WinUI.TableView | Microsoft's current guide points to WinUI.TableView as a modern community option. Toolkit DataGrid still works but is frozen at 7.x. Evaluate both. |
Ribbon | CommandBar / CommandBarFlyout | No first-party Ribbon. Community Toolkit Labs has an experimental Ribbon. |
Menu / MenuItem | MenuBar / MenuBarItem / MenuFlyoutItem | MenuBar for classic menu, MenuFlyout for context |
ContextMenu | MenuFlyout via ContextFlyout | Assign to ContextFlyout on any UIElement |
ToolBar / ToolBarTray | CommandBar + AppBarButton | Replaces toolbar patterns |
StatusBar | InfoBar + custom footer layout | No first-party StatusBar. Use InfoBar for status messages or a footer Grid. |
TabControl | TabView or NavigationView (Top) | TabView for closeable tabs, NavigationView for static |
FlowDocument | RichTextBlock | Partial replacement only |
RichTextBox (editing) | RichEditBox | Rich text editing |
WrapPanel | Built-in on Uno Platform, or Community Toolkit | Uno ships WrapPanel natively |
UniformGrid | Community Toolkit | Not in WinUI by default |
DockPanel | Community Toolkit | Not in WinUI by default |
GroupBox | Expander or custom | No built-in GroupBox |
Label | TextBlock | Use AccessKey on the target control |
MediaElement | MediaPlayerElement | Different API surface |
GridSplitter | Community Toolkit | Not in WinUI by default |
Version note: DataGrid ships in Windows Community Toolkit 7.x and was removed in 8.x. Pin to 7.x or the Uno-ported 7.x package. For new projects, consider WinUI.TableView as a modern alternative that follows current WinUI 3 guidance.
NuGet Packages You Will Likely Need
| Package | Purpose |
|---|---|
CommunityToolkit.WinUI.UI.Controls (7.x) | DataGrid, WrapPanel, DockPanel, UniformGrid, GridSplitter |
Uno.CommunityToolkit.WinUI.* | Uno-ported packages for non-Windows targets |
CommunityToolkit.Mvvm | RelayCommand, ObservableObject, source generators |
Uno.WinUI | Uno Platform's WinUI API implementation |
Uno.Themes.WinUI.Material | Material Design 3 theme support |
Uno.Toolkit.WinUI | NavigationBar, TabBar, DrawerControl, SafeArea |
Patterns That Do Not Exist in WinUI
These require the most effort during migration because they demand architectural changes, not just find-and-replace.
DataTriggers and Style.Triggers
WinUI has no trigger system. The replacement is VisualStateManager with state triggers.
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Background" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style><Border x:Name="MyBorder">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Active">
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind ViewModel.IsActive, Mode=OneWay}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyBorder.Background" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>You can also install Microsoft.Xaml.Behaviors.WinUI.Managed for more complex trigger scenarios, including DataTriggerBehavior.
MultiBinding
WinUI does not support MultiBinding. The most direct replacement is function binding with x:Bind:
<TextBlock Text="{x:Bind local:Converters.FormatFullName(ViewModel.FirstName, ViewModel.LastName), Mode=OneWay}" />public static class Converters
{
public static string FormatFullName(string first, string last)
=> $"{first} {last}";
}Alternative: use a computed property in the ViewModel (public string FullName => $"{FirstName} {LastName}") and raise PropertyChanged for it whenever either source changes.
RoutedUICommand
WinUI does not support routed commands. Replace with [RelayCommand] from CommunityToolkit.Mvvm. WinUI 3 also provides StandardUICommand and XamlUICommand for pre-defined platform commands (Cut, Copy, Paste, Delete) with built-in icons and keyboard accelerators.
Adorners
| Adorner Use Case | WinUI Replacement |
|---|---|
| Validation indicators | TeachingTip, InfoBar, or InputValidation error templates |
| Resize handles | Popup positioned relative to the target element |
| Drag preview | DragItemsStarting event with custom DragUI |
| Overlay decorations | Canvas overlay or Popup layer |
| Watermark / Placeholder | TextBox.PlaceholderText (built-in) |
DynamicResource, StaticResource, and ThemeResource
| WPF | WinUI | Behavior |
|---|---|---|
{StaticResource} | {StaticResource} | Resolved once at load time. Same in both. |
{DynamicResource} | Not available | Use {ThemeResource} instead. |
| No equivalent | {ThemeResource} | Re-evaluated on theme change (Light/Dark). |
If your WPF code uses DynamicResource to swap resources at runtime (not for theming), you will need an alternative: binding to a ViewModel property or using the Composition API.
Binding vs. x:Bind
| Feature | {Binding} | {x:Bind} |
|---|---|---|
| Compile-time validation | No | Yes |
| Default mode | OneWay | OneTime |
| Default source | DataContext | Page/UserControl code-behind |
| Function binding | No | Yes |
| Performance | Reflection-based | Compiled, no reflection |
Default mode gotcha: {x:Bind} defaults to OneTime, not OneWay. Add Mode=OneWay or Mode=TwoWay explicitly if you need live updates.
Styles: Always Use BasedOn
In WinUI 3, always use BasedOn when overriding default control styles. Without it, your style replaces the entire default style rather than extending it.
<Style TargetType="Button" BasedOn="{StaticResource DefaultButtonStyle}">
<Setter Property="Background" Value="Red" />
</Style>RelativeSource AncestorType
WPF's {Binding RelativeSource={RelativeSource AncestorType=...}} has no direct equivalent in WinUI. On Uno Platform, use the Uno Toolkit AncestorSource markup extension.
Resource Dictionaries and Merged Dictionaries
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///Styles/Colors.xaml" />
<ResourceDictionary Source="ms-appx:///Styles/Controls.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>Key differences: in WinUI 3 (Windows App SDK), the default Fluent control styles load automatically from the SDK. You do not need to add XamlControlsResources (that is the UWP + WinUI 2 pattern). Resource paths use the ms-appx:/// scheme. Window.Resources does not exist in WinUI; place window-level resources on the root layout container or on a Page.
Uno Platform Theming
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<MaterialTheme xmlns="using:Uno.Themes" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>Uno Platform supports lightweight styling, which lets you override specific theme resources (colors, corner radii, typography) without replacing entire control templates. Significantly more maintainable than WPF's approach of copying and modifying full control templates.
Dispatcher: Fire-and-Forget and Awaitable
DispatcherQueue.TryEnqueue is the WinUI replacement for Dispatcher.Invoke and BeginInvoke. It is fire-and-forget with no synchronous Invoke equivalent.
To reach the UI thread's DispatcherQueue from a background thread, capture it on the UI thread first. Inside a DependencyObject (Page, UserControl), use this.DispatcherQueue. In App.xaml.cs, capture DispatcherQueue.GetForCurrentThread() at startup and expose it through a static property.
App.MainWindow.DispatcherQueue.TryEnqueue(() =>
{
// UI work
});var tcs = new TaskCompletionSource<bool>(
TaskCreationOptions.RunContinuationsAsynchronously);
if (!App.MainWindow.DispatcherQueue.TryEnqueue(() =>
{
try { /* UI work */ tcs.TrySetResult(true); }
catch (Exception ex) { tcs.TrySetException(ex); }
}))
{
tcs.TrySetException(new InvalidOperationException(
"Failed to enqueue work."));
}
await tcs.Task;The Community Toolkit also ships a DispatcherQueue.EnqueueAsync extension method that handles this wrapping for you.
Complete Find-and-Replace Reference
XAML Attribute Replacements
| Find | Replace With | Context |
|---|---|---|
ContextMenu= | ContextFlyout= | On any UIElement |
{DynamicResource } | {ThemeResource } | Theme-change support |
{x:Static } | {x:Bind } | Static member references |
Visibility="Hidden" | Opacity="0" + IsHitTestVisible="False" | Preserve layout; without IsHitTestVisible the element remains clickable |
MouseLeftButtonDown | PointerPressed | Events |
MouseLeftButtonUp | PointerReleased | Events |
MouseEnter | PointerEntered | Events |
MouseLeave | PointerExited | Events |
MouseMove | PointerMoved | Events |
MouseWheel | PointerWheelChanged | Events |
MouseDoubleClick | DoubleTapped | Events |
Focusable="False" | IsTabStop="False" | Add AllowFocusOnInteraction="False" only if you also need to suppress pointer-interaction focus |
TextWrapping="WrapWithOverflow" | TextWrapping="Wrap" | TextBlock, TextBox |
InputBindings | KeyboardAccelerators | Keyboard shortcuts |
Code-Behind Replacements
| Find | Replace With | Notes |
|---|---|---|
using System.Windows; | using Microsoft.UI.Xaml; | Root types |
using System.Windows.Controls; | using Microsoft.UI.Xaml.Controls; | Controls |
using System.Windows.Media; | using Microsoft.UI.Xaml.Media; | Media |
using System.Windows.Data; | using Microsoft.UI.Xaml.Data; | Data binding |
using System.Windows.Input; | using Microsoft.UI.Xaml.Input; | Input |
Dispatcher.Invoke( | DispatcherQueue.TryEnqueue( | Threading |
Application.Current.Dispatcher | A captured DispatcherQueue | See Dispatcher section |
CaptureMouse() | CapturePointer(e.Pointer) | Inside pointer event handler |
ReleaseMouseCapture() | ReleasePointerCaptures() | Releases all |
Mouse.GetPosition(element) | e.GetCurrentPoint(element).Position | Inside pointer event handler |
MouseEventArgs | PointerRoutedEventArgs | Event handlers |
RoutedUICommand | RelayCommand | CommunityToolkit.Mvvm |
AI Prompt Template for Automated XAML Translation
Copy the prompt template into your AI coding assistant. It encodes every rule from this article so the agent can perform the mechanical translation in one pass. The full prompt covers namespace rules, resource rules, control replacements (including the WinUI.TableView option for DataGrid), property replacements (with the nuanced Focusable mapping), event replacements, trigger replacements, and binding upgrades.
Review: trigger translations (verify VisualStateManager groups reflect your original logic), DataGrid columns (Community Toolkit column types may differ), custom controls (third-party WPF libraries need manual replacement), and resource dictionary paths (verify ms-appx:/// paths resolve correctly).
FAQ
Do I need to rewrite all my XAML from scratch?
No. The majority of WPF XAML (layout panels, core controls, basic styles) transfers with namespace changes and minor property fixes. The heavy lifting is in triggers, MultiBinding, and controls that do not exist in WinUI.
Can I use {Binding} in WinUI, or must I switch to {x:Bind}?
{Binding} still works in WinUI. You are not forced to switch. However, {x:Bind} provides compile-time validation, better performance, and function binding (which replaces MultiBinding). For new or migrated code, {x:Bind} is the recommended choice.
What replaces Visibility.Hidden?
WinUI only has Visible and Collapsed. To keep invisible-but-layout-occupying behavior, set Opacity="0" while keeping Visibility="Visible", and also set IsHitTestVisible="False" so the element is not clickable. If the control would otherwise receive focus from pointer interaction and you want to block that too, add AllowFocusOnInteraction="False".
Do I need to add XamlControlsResources to my WinUI 3 App.xaml?
Usually no. In a WinUI 3 (Windows App SDK) project, the default Fluent control styles load automatically from the SDK. XamlControlsResources is primarily the UWP + WinUI 2 pattern. If you include it (for example, sharing dictionaries with a WinUI 2 codebase), add it as the first merged dictionary so it does not override your custom styles.
How do I migrate WPF's Dispatcher pattern?
WinUI 3 has no built-in App.MainWindow; the convention is to capture your window in App.OnLaunched and expose it as a public static property. Replace Dispatcher.Invoke(...) with DispatcherQueue.TryEnqueue(...). For awaitable dispatch, wrap with a TaskCompletionSource or use the Community Toolkit EnqueueAsync extension.
Which Community Toolkit version ships DataGrid?
DataGrid is in Windows Community Toolkit 7.x and was removed in 8.x. Pin to 7.x or the Uno-ported 7.x package. Microsoft's current WPF-to-WinUI 3 guidance also points to WinUI.TableView as a community-maintained alternative worth evaluating.
Is there an automated migration tool from Microsoft?
There is no automated WPF-to-WinUI migration tool from Microsoft as of 2026. The .NET Upgrade Assistant handles .NET Framework to .NET upgrades but does not translate WPF XAML to WinUI XAML.
Does Uno Platform add extra controls beyond WinUI?
Yes. The Uno Toolkit (Uno.Toolkit.WinUI) includes NavigationBar, TabBar, DrawerControl, SafeArea, and more. The Community Toolkit controls also work across all Uno Platform targets via the Uno-ported packages.
- Migrate WPF App Patterns to WinUI 3 →
- User Interface Migration (Microsoft Learn) →
- Microsoft.UI.Xaml.Controls Namespace →
- Visibility Enum (Microsoft.UI.Xaml) →
- DispatcherQueue.TryEnqueue →
- Threading Functionality Migration →
- XAML Theme Resources →
- {x:Bind} Markup Extension →
- Functions in x:Bind →
- RelayCommand (CommunityToolkit) →
- DispatcherQueue.EnqueueAsync (CommunityToolkit) →
- Uno Platform 6.5 Release →
- WPF to WinUI Equivalents (Uno Docs) →
- Uno.Themes (GitHub) →
- Ancestor Binding Helper (Uno Toolkit) →
- WinUI.TableView (Community Project) →
Subscribe to Our Blog
Subscribe via RSS
Back to Top