Winui3 Migration Guide
GitHubOfficialFirst committed by niels9001Distributed by GitHub
- Skill
- Guidelines
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The WinUI 3 Migration Guide provides developers with a structured approach to transitioning UWP applications to the Windows App SDK. It details critical API changes, namespace updates, and architectural shifts required for modernizing desktop applications. The guide covers essential areas including threading, windowing, dialog management, and background tasks, while highlighting common pitfalls encountered during the migration process.
What it does
- Maps legacy Windows.UI.Xaml namespaces to Microsoft.UI.Xaml equivalents.
- Provides code patterns for replacing deprecated UWP APIs with WinUI 3 alternatives.
- Explains the transition from CoreDispatcher to DispatcherQueue for thread management.
- Details the initialization of pickers and dialogs using window handles.
- Outlines the migration path for background tasks and app lifecycle management.
- Provides a checklist for updating project configurations and test suites.
When to use it
- When porting an existing UWP application to WinUI 3.
- When debugging runtime errors caused by using legacy UWP patterns in a WinUI 3 environment.
- When verifying that AI-generated code adheres to WinUI 3 API standards.
- When setting up unit testing for WinUI 3 desktop applications.
Advantages
- Reduces migration friction by providing direct before-and-after code comparisons.
- Addresses common errors such as missing XamlRoot or incorrect dispatcher usage.
- Centralizes complex interop requirements for window management and file pickers.
- Provides a clear roadmap for updating project files and test infrastructure.
Usage examples
- “How do I show a ContentDialog in WinUI 3?”
- The guide explains that you must set the XamlRoot property on the ContentDialog instance to the current window's content root before calling ShowAsync.
- “What is the WinUI 3 replacement for CoreDispatcher?”
- The guide instructs to use DispatcherQueue.TryEnqueue, providing examples for both standard and priority-based execution.
- “How do I initialize a FileOpenPicker in WinUI 3?”
- The guide provides the pattern for using WinRT.Interop.InitializeWithWindow to associate the picker with the application's window handle.
- “Why is my unit test failing in WinUI 3?”
- The guide explains the need to use the WinUI 3 test project template and the [UITestMethod] attribute for tests interacting with XAML elements.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/github/winui3-migration-guide/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip winui3-migration-guide.zip -d .agents/skills
Documentation by niels9001
WinUI 3 Migration Guide
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.
Namespace Changes
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) |
Top 3 Most Common Copilot Mistakes
1. ContentDialog Without XamlRoot
// ❌ 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();2. MessageDialog Instead of ContentDialog
// ❌ 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
}3. CoreDispatcher Instead of DispatcherQueue
// ❌ 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;
});Windowing Migration
Window Reference
// ❌ 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.MainWindowWindow Management
| 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() |
Title Bar
| UWP API | WinUI 3 API |
|---|---|
CoreApplicationViewTitleBar | AppWindowTitleBar |
CoreApplicationView.TitleBar.ExtendViewIntoTitleBar | AppWindow.TitleBar.ExtendsContentIntoTitleBar |
Dialogs and Pickers Migration
File/Folder Pickers
// ❌ 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();Threading Migration
| 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.
Background Tasks Migration
// ❌ 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
}App Settings Migration
| Scenario | Packaged App | Unpackaged App |
|---|---|---|
| Simple settings | ApplicationData.Current.LocalSettings | JSON file in LocalApplicationData |
| Local file storage | ApplicationData.Current.LocalFolder | Environment.GetFolderPath(SpecialFolder.LocalApplicationData) |
GetForCurrentView() Replacements
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 |
Testing Migration
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.
Migration Checklist
[ ] 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
Files
- ATTRIBUTION.mdAdded by AutoGineer879 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md8.8 KiB
Requirements and compatibility
Written for: GitHub Copilot
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- First committed by
niels9001
- Publisher
- GitHub (Official)
- Distributed by
- GitHub
- Source
- github/awesome-copilot · skills/winui3-migration-guide · commit 797337f
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Contributors
- niels9001
AutoGineer is not affiliated with or endorsed by niels9001 or GitHub.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download winui3-migration-guide.zip