Back to Uno

WPF to WinUI XAML Equivalents Reference

doc/articles/wpf-winui-equivalents.md

6.6-release-branch-cut20.6 KB
Original Source

WPF to WinUI XAML Equivalents Reference

This reference provides a comprehensive mapping of WPF namespaces, controls, XAML syntax, events, and patterns to their WinUI 3 / Uno Platform equivalents. Use it as a lookup when migrating WPF applications.

[!TIP] For architectural migration guidance (MVVM, navigation, data access), see Migrating WPF Apps to Web.

Namespace Mapping

WPF NamespaceWinUI 3 NamespaceNotes
System.WindowsMicrosoft.UI.XamlRoot namespace
System.Windows.ControlsMicrosoft.UI.Xaml.ControlsCore controls
System.Windows.Controls.PrimitivesMicrosoft.UI.Xaml.Controls.PrimitivesLow-level primitives
System.Windows.MediaMicrosoft.UI.Xaml.MediaBrushes, transforms
System.Windows.Media.AnimationMicrosoft.UI.Xaml.Media.AnimationStoryboard, animations
System.Windows.Media.ImagingMicrosoft.UI.Xaml.Media.ImagingBitmapImage, WriteableBitmap
System.Windows.Media.Media3DMicrosoft.UI.Xaml.Media.Media3D (partial equivalent)Supports 3D transforms/projection (for example CompositeTransform3D, Matrix3D, PerspectiveTransform3D), but not WPF-style Viewport3D / 3D scene graph APIs
System.Windows.ShapesMicrosoft.UI.Xaml.ShapesRectangle, Ellipse, Path
System.Windows.DataMicrosoft.UI.Xaml.DataBinding, IValueConverter
System.Windows.InputMicrosoft.UI.Xaml.InputPointer, keyboard, focus
System.Windows.NavigationNo direct equivalentUse Frame.Navigate()
System.Windows.DocumentsLimitedRichTextBlock + Paragraph
System.Windows.MarkupMicrosoft.UI.Xaml.MarkupXAML parsing, markup extensions
System.Windows.AutomationMicrosoft.UI.Xaml.AutomationAccessibility / UI Automation
System.Windows.InteropMicrosoft.UI.Xaml.HostingInterop / XAML Islands
System.Windows.ThreadingMicrosoft.UI.DispatchingDispatcher becomes DispatcherQueue

XAML Declaration Syntax

WPFWinUI
xmlns:local="clr-namespace:MyApp"xmlns:local="using:MyApp"
xmlns:local="clr-namespace:MyApp;assembly=MyLib"xmlns:local="using:MyApp" (assembly inferred)

Control Mappings

Controls That Transfer Directly

These controls exist in both WPF and WinUI and typically require only a namespace change:

Button, TextBox, TextBlock, CheckBox, RadioButton, ComboBox, ListBox, ListView, Grid, StackPanel, Border, ScrollViewer, Canvas, Image, Slider, ProgressBar, ToolTip/ToolTipService, Expander, TreeView.

WinUI-Only Additions You May Want to Adopt

The following controls do not have direct equivalents in WPF but are often valuable to introduce when modernizing your UI with WinUI / Uno Platform:

NavigationView, NumberBox, InfoBar, ProgressRing, ToggleSwitch, HyperlinkButton, GridView.

Controls Requiring Replacement

WPF ControlWinUI / Uno ReplacementNotes
DataGridCommunity Toolkit DataGridSimilar API, not identical. In WinUI 3 (Windows App SDK), use CommunityToolkit.WinUI.UI.Controls; for Uno Platform non-Windows targets, use the Uno-ported toolkit packages (Uno.CommunityToolkit.WinUI.*).
RibbonCommandBar or NavigationViewNo Ribbon in WinUI
Menu / MenuItemMenuBar / MenuBarItem / MenuFlyoutItemMenuBar for top-level menus; MenuFlyout for context menus
ContextMenuMenuFlyout via ContextFlyout propertyAssign to ContextFlyout on any UIElement
ToolBar / ToolBarTrayCommandBar + AppBarButton
StatusBarCustom Grid / StackPanel or InfoBarNo StatusBar control in WinUI
TabControlTabView or NavigationView (Top mode)TabView supports closable tabs
DocumentViewerWebView2Can display PDFs in WebView2; XPS requires conversion or a dedicated/third-party viewer
FlowDocumentRichTextBlockPartial replacement only
RichTextBoxRichEditBoxRich text editing
WrapPanelWrapPanel (built-in on Uno Platform) or Community Toolkit WrapPanelBuilt-in on Uno Platform; otherwise see package guidance below.
UniformGridCommunity Toolkit UniformGridNot in WinUI by default; see package guidance below.
DockPanelCommunity Toolkit DockPanelNot in WinUI by default; see package guidance below.
GroupBoxExpander or a custom UserControl/templated ContentControlNo built-in GroupBox in WinUI; use a custom header + border presentation when needed
LabelTextBlockUse TextBlock for the visual label; for WPF Label.Target-style association, use AutomationProperties.LabeledBy on the labeled control. AccessKey can be added separately for keyboard access.
MediaElementMediaPlayerElementDifferent API surface
Window (standalone)WindowWindow host; content is typically a Page/root UIElement. Use ContentDialog for modal windows.
GridSplitterCommunity Toolkit GridSplitterSee package guidance below.
CalendarCalendarViewSimilar functionality with updated API
ListBoxListBox or ListViewListBox exists in WinUI/Uno; prefer ListView when you need richer built-in list item presentation or interaction features

Package guidance for Community Toolkit controls in this table: in WinUI 3 (Windows App SDK), use CommunityToolkit.WinUI.UI.Controls; for Uno Platform non-Windows targets, install the matching Uno package for the control you use, such as Uno.CommunityToolkit.WinUI.UI.Controls for controls like DockPanel and GridSplitter, or Uno.CommunityToolkit.WinUI.UI.Controls.DataGrid for DataGrid. See Uno Community Toolkit packages for the authoritative package list and version guidance.

Useful NuGet Packages

PackagePurpose
CommunityToolkit.WinUI.UI.ControlsDataGrid, WrapPanel, DockPanel, UniformGrid. Note: DataGrid and some related controls are available in Windows Community Toolkit 7.x; they were removed from 8.x.
CommunityToolkit.MvvmRelayCommand, ObservableObject, source generators
Uno.Material.WinUI, Uno.Cupertino.WinUI, Uno.Simple.WinUIMaterial, Cupertino, or simple theme support
Uno.Toolkit.WinUIAdditional cross-platform controls and helpers

Property and Value Mappings

WPF Property / ValueWinUI EquivalentContext
Visibility.HiddenNot availableUse Opacity="0" together with IsHitTestVisible="False" (and, for focusable controls, IsTabStop="False") to be invisible, non-interactive, but still layout-occupying.
TextWrapping.WrapWithOverflowTextWrapping.WrapWinUI does not distinguish
FocusableIsTabStop and, when preventing interaction focus, AllowFocusOnInteractionIsTabStop controls keyboard tab navigation; to also prevent focus via pointer interaction in WinUI/Uno, typically use AllowFocusOnInteraction="False" as well (and IsTabStop="False" where applicable).

Event Mappings

Pointer Events (Replacing Mouse Events)

WPF EventWinUI EventArgs Type
MouseLeftButtonDownPointerPressedPointerRoutedEventArgs
MouseLeftButtonUpPointerReleasedPointerRoutedEventArgs
MouseMovePointerMovedPointerRoutedEventArgs
MouseEnterPointerEnteredPointerRoutedEventArgs
MouseLeavePointerExitedPointerRoutedEventArgs
MouseWheelPointerWheelChangedPointerRoutedEventArgs
MouseDoubleClickDoubleTappedDoubleTappedRoutedEventArgs
PreviewMouseDownPointerPressedNo direct WPF-style tunneling/preview pointer event in WinUI

[!NOTE] WinUI does not provide WPF-style PreviewMouse* tunneling events for pointer/mouse input. If you need to listen for a bubbling event even after a child marks it handled, use AddHandler with handledEventsToo: true. This does not reproduce WPF-style preview ordering (parent before child).

Keyboard Events

WPF EventWinUI EventArgs Type
KeyDownKeyDownKeyRoutedEventArgs
KeyUpKeyUpKeyRoutedEventArgs
PreviewKeyDownUno only (WASM/SKIA): PreviewKeyDownKeyRoutedEventArgs
PreviewKeyUpUno only (WASM/SKIA): PreviewKeyUpKeyRoutedEventArgs

[!NOTE] Standard WinUI 3 does not expose WPF-style preview keyboard events. On Uno, PreviewKeyDown and PreviewKeyUp are available only on some targets (for example, WASM/SKIA), so treat them as platform-specific rather than general WinUI equivalents. When you need a cross-target or WinUI 3-compatible alternative, use KeyDown and KeyUp, and validate event ordering on your target platforms when the distinction matters.

Mouse Capture

WPFWinUINotes
element.CaptureMouse()element.CapturePointer(e.Pointer)Typically used inside a pointer event where e.Pointer is available
element.ReleaseMouseCapture()element.ReleasePointerCaptures()General equivalent when you do not have the original Pointer; if you need to release a specific pointer later, store it and call element.ReleasePointerCapture(pointer)
Mouse.GetPosition(element)e.GetCurrentPoint(element).PositionUse within pointer event handling

XAML Syntax Translations

Resource and Binding Markup

WPFWinUINotes
{StaticResource Key}{StaticResource Key}Identical - resolved once at load
{DynamicResource Key}{ThemeResource Key}Re-evaluated on theme changes (Light/Dark)
{x:Static ns:Type.Member}{x:Bind ns:Type.Member}Common option for static member references; enums/values can often use direct ns:Type.Member or literals
{Binding Path=X}{x:Bind ViewModel.X, Mode=OneWay}See binding comparison below
{Binding RelativeSource={RelativeSource AncestorType=...}}Uno Toolkit AncestorSourceSee Ancestor/ItemsControl binding

Binding Technology Comparison

Feature{Binding}{x:Bind}
Compile-time validationNoYes
Default modeDepends on target property metadata (often OneWay; some are TwoWay)OneTime
Default sourceDataContextPage / UserControl code-behind
Function bindingNoYes
PerformanceReflection-basedCompiled, no reflection
MultiBindingNot in WinUIUse function binding

[!IMPORTANT] {x:Bind} defaults to OneTime, not OneWay. Always specify Mode=OneWay for properties that should update.

Patterns Without Direct WinUI Equivalents

Style.Triggers and DataTriggers

WinUI does not support Style.Triggers, DataTrigger, EventTrigger, or MultiDataTrigger. Replace with VisualStateManager:

WPF:

xml
<Style TargetType="Border">
  <Style.Triggers>
    <DataTrigger Binding="{Binding IsActive}" Value="True">
      <Setter Property="Background" Value="Green" />
    </DataTrigger>
  </Style.Triggers>
</Style>

WinUI equivalent:

xml
<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>

MultiBinding

WinUI does not support MultiBinding. Use x:Bind with function binding:

xml
<TextBlock Text="{x:Bind local:Converters.FormatFullName(ViewModel.FirstName, ViewModel.LastName), Mode=OneWay}" />
csharp
public static class Converters
{
    public static string FormatFullName(string first, string last)
        => $"{first} {last}";
}

RoutedUICommand

Replace RoutedUICommand and CommandBinding with ICommand implementations. Using CommunityToolkit.Mvvm:

csharp
[RelayCommand(CanExecute = nameof(CanSave))]
private void Save() { /* save logic */ }

private bool CanSave() => IsDirty;

WinUI 3 also offers StandardUICommand and XamlUICommand for predefined operations (Cut, Copy, Paste) with built-in icons and keyboard accelerators.

Adorners

WinUI does not have an Adorner layer. Use these alternatives:

Adorner Use CaseWinUI Replacement
Validation indicatorsTeachingTip, InfoBar, or input validation templates
Resize handlesPopup positioned relative to target
Drag previewDragItemsStarting event with custom DragUI
Overlay decorationsCanvas overlay or Popup layer
Watermark / PlaceholderTextBox.PlaceholderText (built-in)

Resource Dictionaries

xml
<Application.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <!-- Required: default Fluent styles -->
      <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
      <!-- Your custom resources -->
      <ResourceDictionary Source="ms-appx:///Styles/Colors.xaml" />
    </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</Application.Resources>

Key differences from WPF:

  • XamlControlsResources must be the first merged dictionary to provide default styles. Omitting it leaves controls with no visual appearance.
  • Resource paths use ms-appx:/// protocol instead of relative paths.
  • Window.Resources does not exist in WinUI. Place window-level resources on root layout containers or Page.

Implicit Styles and BasedOn

Always use BasedOn when overriding default control styles. Without it, your style replaces the entire default style rather than extending it:

xml
<Style TargetType="Button" BasedOn="{StaticResource DefaultButtonStyle}">
  <Setter Property="Background" Value="Red" />
</Style>

Common API Replacements

WPF CodeWinUI ReplacementNotes
Application.Current.Dispatcher.Invoke(...)App.MainWindow.DispatcherQueue.TryEnqueue(...)Fire-and-forget; no synchronous Invoke. See awaitable example below.
Application.Current.MainWindowApp.MainWindow (captured at startup)Use the app's main window reference in WinUI/Uno.
Clipboard (System.Windows)Windows.ApplicationModel.DataTransfer.ClipboardDifferent API surface
MessageBox.Show()ContentDialog with XamlRootNo MessageBox in WinUI

For awaitable dispatch, wrap DispatcherQueue.TryEnqueue(...) with a TaskCompletionSource:

csharp
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);

if (!App.MainWindow.DispatcherQueue.TryEnqueue(() =>
{
    try
    {
        /* work */
        tcs.TrySetResult(true);
    }
    catch (Exception ex)
    {
        tcs.TrySetException(ex);
    }
}))
{
    tcs.TrySetException(new InvalidOperationException("Failed to enqueue work on the DispatcherQueue."));
}

await tcs.Task;

Find-and-Replace Quick Reference

XAML Attribute Replacements

FindReplace WithNotes
ContextMenu=ContextFlyout=
{DynamicResource{ThemeResource
{x:Static{x:Bind
Visibility="Hidden" (layout-preserving)Opacity="0" with IsHitTestVisible="False"Keeps layout space; combine with IsTabStop="False" for focusable controls
Visibility="Hidden" (remove from layout)Visibility="Collapsed"Collapses space like WPF Visibility="Collapsed"
MouseLeftButtonDownPointerPressed
MouseLeftButtonUpPointerReleased
MouseEnterPointerEntered
MouseLeavePointerExited
MouseMovePointerMoved
MouseWheelPointerWheelChanged
Focusable="True"IsTabStop="True"
TextWrapping="WrapWithOverflow"TextWrapping="Wrap"
MediaElementMediaPlayerElement
InputBindingsKeyboardAccelerators
KeyBindingKeyboardAccelerator

Code-Behind Replacements

FindReplace With
using System.Windows;using Microsoft.UI.Xaml;
using System.Windows.Controls;using Microsoft.UI.Xaml.Controls;
using System.Windows.Media;using Microsoft.UI.Xaml.Media;
using System.Windows.Data;using Microsoft.UI.Xaml.Data;
using System.Windows.Input;using Microsoft.UI.Xaml.Input;
Dispatcher.Invoke(DispatcherQueue.TryEnqueue(
MouseEventArgsPointerRoutedEventArgs
KeyEventArgsKeyRoutedEventArgs
RoutedUICommandRelayCommand (CommunityToolkit.Mvvm)
CommandBindingRemove; bind ICommand directly

AI Prompt Template

Use this prompt with an AI coding assistant to automate the mechanical translation of WPF XAML files:

text
You are a WPF-to-WinUI XAML migration assistant. Translate the following WPF XAML
file to WinUI 3 XAML compatible with Uno Platform.

Apply ALL of the following rules:

NAMESPACE RULES:
- Keep the default xmlns as-is
- Replace clr-namespace references with "using:" syntax
- Replace System.Windows.* with Microsoft.UI.Xaml.*

RESOURCE RULES:
- Replace {DynamicResource X} with {ThemeResource X}
- Replace {x:Static X} with {x:Bind X}
- Keep {StaticResource X} as-is

CONTROL REPLACEMENTS:
- Menu/MenuItem -> MenuBar/MenuBarItem/MenuFlyoutItem

- ContextMenu -> ContextFlyout with MenuFlyout
- ToolBar -> CommandBar with AppBarButton
- StatusBar -> Grid at bottom of layout
- TabControl -> TabView or NavigationView (Top mode)
- DataGrid -> CommunityToolkit DataGrid
- Label -> TextBlock
- MediaElement -> MediaPlayerElement

PROPERTY REPLACEMENTS:
- Visibility="Hidden" -> WinUI has no direct `Hidden` state; when layout must be preserved, use `Opacity="0"` with `Visibility="Visible"` and also set `IsHitTestVisible="False"`; for focusable controls also set `IsTabStop="False"` and `AllowFocusOnInteraction="False"` so the element is not invisible-but-interactive; use `Visibility="Collapsed"` only when removing the element from layout is acceptable
- TextWrapping="WrapWithOverflow" -> TextWrapping="Wrap"
- Focusable -> IsTabStop

EVENT REPLACEMENTS:
- Mouse* events -> Pointer* equivalents
- Remove Preview* tunneling events

TRIGGER REPLACEMENTS:
- Remove Style.Triggers, DataTrigger, EventTrigger
- Create VisualStateManager.VisualStateGroups with StateTrigger

BINDING UPGRADES:
- Convert {Binding Path=X} to {x:Bind ViewModel.X, Mode=OneWay}
- Replace MultiBinding with x:Bind function binding

OUTPUT: Complete translated XAML with a list of manual follow-up items.

WPF XAML to translate:
```xml
<!-- Paste WPF XAML here -->
<PASTE WPF XAML HERE>
```

FAQ

Do I need to rewrite all my XAML from scratch?

No. The majority of WPF XAML transfers with namespace changes and minor property fixes. The heavy lifting is in triggers, MultiBinding, and controls that don't exist in WinUI.

Can I keep using {Binding} or must I switch to {x:Bind}?

{Binding} still works and is not mandatory to replace. However, {x:Bind} provides compile-time validation, better performance, and function binding (which replaces MultiBinding). For new or migrated code, {x:Bind} is recommended.

What replaces Visibility.Hidden?

WinUI only has Visible and Collapsed. For invisible-but-layout-occupying behavior, set Opacity="0" while keeping Visibility="Visible", and also set IsHitTestVisible="False". If the control can receive focus, also set IsTabStop="False" and AllowFocusOnInteraction="False" so it does not remain invisible but interactive.

How do I handle preview/tunneling events?

WinUI 3 does not generally provide WPF-style preview/tunneling events. In Uno Platform, some preview keyboard events such as PreviewKeyDown and PreviewKeyUp are available on specific targets only, so they should not be treated as a general WinUI 3 migration equivalent. For cross-target and WinUI 3-compatible code, use KeyDown/KeyUp instead. WPF-style preview mouse/pointer events such as PreviewMouseDown do not generally have direct equivalents; use the corresponding bubbling event (for example, PointerPressed) and, if you need to observe events that were already marked handled, register with AddHandler(..., handledEventsToo: true).

How do I migrate the Dispatcher pattern?

Replace Application.Current.Dispatcher.Invoke(...) with App.MainWindow.DispatcherQueue.TryEnqueue(...). The DispatcherQueue API is asynchronous by default and has no synchronous Invoke method.

Does Uno Platform add controls beyond WinUI?

Yes. The Uno Toolkit includes NavigationBar, TabBar, DrawerControl, SafeArea, and more. The Community Toolkit controls (DataGrid, WrapPanel, DockPanel) also work across all Uno Platform targets.