| name | description |
|---|---|
winui3-migration-guide |
UWP-to-WinUI 3 migration reference. Maps legacy UWP APIs to correct Windows App SDK equivalents with before/after code snippets. Covers namespace changes, threading (CoreDispatcher to DispatcherQueue), windowing (CoreWindow to AppWindow), dialogs, pickers, sharing, printing, background tasks, and the most common Copilot code generation mistakes. |
Use this skill when migrating UWP apps to WinUI 3 / Windows App SDK, or when verifying that generated code uses correct WinUI 3 APIs instead of legacy UWP patterns.
All Windows.UI.Xaml.* namespaces move to Microsoft.UI.Xaml.*:
| UWP Namespace | WinUI 3 Namespace |
|---|---|
Windows.UI.Xaml |
Microsoft.UI.Xaml |
Windows.UI.Xaml.Controls |
Microsoft.UI.Xaml.Controls |
Windows.UI.Xaml.Media |
Microsoft.UI.Xaml.Media |
Windows.UI.Xaml.Input |
Microsoft.UI.Xaml.Input |
Windows.UI.Xaml.Data |
Microsoft.UI.Xaml.Data |
Windows.UI.Xaml.Navigation |
Microsoft.UI.Xaml.Navigation |
Windows.UI.Xaml.Shapes |
Microsoft.UI.Xaml.Shapes |
Windows.UI.Composition |
Microsoft.UI.Composition |
Windows.UI.Input |
Microsoft.UI.Input |
Windows.UI.Colors |
Microsoft.UI.Colors |
Windows.UI.Text |
Microsoft.UI.Text |
Windows.UI.Core |
Microsoft.UI.Dispatching (for dispatcher) |
// ❌ WRONG — Throws InvalidOperationException in WinUI 3
var dialog = new ContentDialog
{
Title = "Error",
Content = "Something went wrong.",
CloseButtonText = "OK"
};
await dialog.ShowAsync();// ✅ CORRECT — Set XamlRoot before showing
var dialog = new ContentDialog
{
Title = "Error",
Content = "Something went wrong.",
CloseButtonText = "OK",
XamlRoot = this.Content.XamlRoot // Required in WinUI 3
};
await dialog.ShowAsync();// ❌ WRONG — UWP API, not available in WinUI 3 desktop
var dialog = new Windows.UI.Popups.MessageDialog("Are you sure?", "Confirm");
await dialog.ShowAsync();// ✅ CORRECT — Use ContentDialog
var dialog = new ContentDialog
{
Title = "Confirm",
Content = "Are you sure?",
PrimaryButtonText = "Yes",
CloseButtonText = "No",
XamlRoot = this.Content.XamlRoot
};
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
// User confirmed
}// ❌ WRONG — CoreDispatcher does not exist in WinUI 3
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
StatusText.Text = "Done";
});// ✅ CORRECT — Use DispatcherQueue
DispatcherQueue.TryEnqueue(() =>
{
StatusText.Text = "Done";
});
// With priority:
DispatcherQueue.TryEnqueue(DispatcherQueuePriority.High, () =>
{
ProgressBar.Value = 100;
});// ❌ WRONG — Window.Current does not exist in WinUI 3
var currentWindow = Window.Current;// ✅ CORRECT — Use a static property in App
public partial class App : Application
{
public static Window MainWindow { get; private set; }
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
MainWindow = new MainWindow();
MainWindow.Activate();
}
}
// Access anywhere: App.MainWindow| UWP API | WinUI 3 API |
|---|---|
ApplicationView.TryResizeView() |
AppWindow.Resize() |
AppWindow.TryCreateAsync() |
AppWindow.Create() |
AppWindow.TryShowAsync() |
AppWindow.Show() |
AppWindow.TryConsolidateAsync() |
AppWindow.Destroy() |
AppWindow.RequestMoveXxx() |
AppWindow.Move() |
AppWindow.GetPlacement() |
AppWindow.Position property |
AppWindow.RequestPresentation() |
AppWindow.SetPresenter() |
| UWP API | WinUI 3 API |
|---|---|
CoreApplicationViewTitleBar |
AppWindowTitleBar |
CoreApplicationView.TitleBar.ExtendViewIntoTitleBar |
AppWindow.TitleBar.ExtendsContentIntoTitleBar |
// ❌ WRONG — UWP style, no window handle
var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".txt");
var file = await picker.PickSingleFileAsync();// ✅ CORRECT — Initialize with window handle
var picker = new FileOpenPicker();
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);
picker.FileTypeFilter.Add(".txt");
var file = await picker.PickSingleFileAsync();| UWP Pattern | WinUI 3 Equivalent |
|---|---|
CoreDispatcher.RunAsync(priority, callback) |
DispatcherQueue.TryEnqueue(priority, callback) |
Dispatcher.HasThreadAccess |
DispatcherQueue.HasThreadAccess |
CoreDispatcher.ProcessEvents() |
No equivalent — restructure async code |
CoreWindow.GetForCurrentThread() |
Not available — use DispatcherQueue.GetForCurrentThread() |
Key difference: UWP uses ASTA (Application STA) with built-in reentrancy blocking. WinUI 3 uses standard STA without this protection. Watch for reentrancy issues when async code pumps messages.
// ❌ WRONG — UWP IBackgroundTask
public sealed class MyTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance) { }
}// ✅ CORRECT — Windows App SDK AppLifecycle
using Microsoft.Windows.AppLifecycle;
// Register for activation
var args = AppInstance.GetCurrent().GetActivatedEventArgs();
if (args.Kind == ExtendedActivationKind.AppNotification)
{
// Handle background activation
}| Scenario | Packaged App | Unpackaged App |
|---|---|---|
| Simple settings | ApplicationData.Current.LocalSettings |
JSON file in LocalApplicationData |
| Local file storage | ApplicationData.Current.LocalFolder |
Environment.GetFolderPath(SpecialFolder.LocalApplicationData) |
All GetForCurrentView() patterns are unavailable in WinUI 3 desktop apps:
| UWP API | WinUI 3 Replacement |
|---|---|
UIViewSettings.GetForCurrentView() |
Use AppWindow properties |
ApplicationView.GetForCurrentView() |
AppWindow.GetFromWindowId(windowId) |
DisplayInformation.GetForCurrentView() |
Win32 GetDpiForWindow() or XamlRoot.RasterizationScale |
CoreApplication.GetCurrentView() |
Not available — track windows manually |
SystemNavigationManager.GetForCurrentView() |
Handle back navigation in NavigationView directly |
UWP unit test projects do not work with WinUI 3. You must migrate to the WinUI 3 test project templates.
| UWP | WinUI 3 |
|---|---|
| Unit Test App (Universal Windows) | Unit Test App (WinUI in Desktop) |
| Standard MSTest project with UWP types | Must use WinUI test app for Xaml runtime |
[TestMethod] for all tests |
[TestMethod] for logic, [UITestMethod] for XAML/UI tests |
| Class Library (Universal Windows) | Class Library (WinUI in Desktop) |
// ✅ WinUI 3 unit test — use [UITestMethod] for any XAML interaction
[UITestMethod]
public void TestMyControl()
{
var control = new MyLibrary.MyUserControl();
Assert.AreEqual(expected, control.MyProperty);
}Key: The [UITestMethod] attribute tells the test runner to execute the test on the XAML UI thread, which is required for instantiating any Microsoft.UI.Xaml type.
- Replace all
Windows.UI.Xaml.*using directives withMicrosoft.UI.Xaml.* - Replace
Windows.UI.ColorswithMicrosoft.UI.Colors - Replace
CoreDispatcher.RunAsyncwithDispatcherQueue.TryEnqueue - Replace
Window.CurrentwithApp.MainWindowstatic property - Add
XamlRootto allContentDialoginstances - Initialize all pickers with
InitializeWithWindow.Initialize(picker, hwnd) - Replace
MessageDialogwithContentDialog - Replace
ApplicationView/CoreWindowwithAppWindow - Replace
CoreApplicationViewTitleBarwithAppWindowTitleBar - Replace all
GetForCurrentView()calls withAppWindowequivalents - Update interop for Share and Print managers
- Replace
IBackgroundTaskwithAppLifecycleactivation - Update project file: TFM to
net10.0-windows10.0.22621.0, add<UseWinUI>true</UseWinUI> - Migrate unit tests to Unit Test App (WinUI in Desktop) project; use
[UITestMethod]for XAML tests - Test both packaged and unpackaged configurations