SKILL.md
readonly只读
name
winui3-migration-guide
description
UWP 到 WinUI 3 迁移参考。将旧版 UWP API 映射到正确的 Windows App SDK 等效项,并附有前后代码片段。涵盖命名空间更改、线程处理(CoreDispatcher 到 DispatcherQueue)、窗口管理(CoreWindow 到 AppWindow)、对话框、选择器、共享、打印、后台任务以及最常见的 Copilot 代码生成错误。
WinUI 3 迁移指南
在将 UWP 应用迁移到 WinUI 3 / Windows App SDK 时,或验证生成的代码是否使用正确的 WinUI 3 API 而非旧版 UWP 模式时,请使用此技能。
命名空间更改
所有 Windows.UI.Xaml.* 命名空间移至 Microsoft.UI.Xaml.*:
| UWP 命名空间 | WinUI 3 命名空间 |
|---|---|
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(用于调度器) |
最常见的 3 个 Copilot 错误
1. ContentDialog 缺少 XamlRoot
// ❌ 错误 — 在 WinUI 3 中抛出 InvalidOperationException
var dialog = new ContentDialog
{
Title = "错误",
Content = "出现问题。",
CloseButtonText = "确定"
};
await dialog.ShowAsync();
// ✅ 正确 — 显示前设置 XamlRoot
var dialog = new ContentDialog
{
Title = "错误",
Content = "出现问题。",
CloseButtonText = "确定",
XamlRoot = this.Content.XamlRoot // WinUI 3 中必需
};
await dialog.ShowAsync();
2. 使用 MessageDialog 而非 ContentDialog
// ❌ 错误 — UWP API,在 WinUI 3 桌面应用中不可用
var dialog = new Windows.UI.Popups.MessageDialog("确定吗?", "确认");
await dialog.ShowAsync();
// ✅ 正确 — 使用 ContentDialog
var dialog = new ContentDialog
{
Title = "确认",
Content = "确定吗?",
PrimaryButtonText = "是",
CloseButtonText = "否",
XamlRoot = this.Content.XamlRoot
};
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
// 用户已确认
}
3. 使用 CoreDispatcher 而非 DispatcherQueue
// ❌ 错误 — CoreDispatcher 在 WinUI 3 中不存在
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
StatusText.Text = "完成";
});
// ✅ 正确 — 使用 DispatcherQueue
DispatcherQueue.TryEnqueue(() =>
{
StatusText.Text = "完成";
});
// 带优先级:
DispatcherQueue.TryEnqueue(DispatcherQueuePriority.High, () =>
{
ProgressBar.Value = 100;
});
窗口迁移
窗口引用
// ❌ 错误 — Window.Current 在 WinUI 3 中不存在
var currentWindow = Window.Current;
// ✅ 正确 — 在 App 中使用静态属性
public partial class App : Application
{
public static Window MainWindow { get; private set; }
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
MainWindow = new MainWindow();
MainWindow.Activate();
}
}
// 任意位置访问: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 属性 |
AppWindow.RequestPresentation() |
AppWindow.SetPresenter() |
标题栏
| UWP API | WinUI 3 API |
|---|---|
CoreApplicationViewTitleBar |
AppWindowTitleBar |
CoreApplicationView.TitleBar.ExtendViewIntoTitleBar |
AppWindow.TitleBar.ExtendsContentIntoTitleBar |
对话框和选择器迁移
文件/文件夹选择器
// ❌ 错误 — UWP 风格,无窗口句柄
var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".txt");
var file = await picker.PickSingleFileAsync();
// ✅ 正确 — 使用窗口句柄初始化
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 模式 | WinUI 3 等效项 |
|---|---|
CoreDispatcher.RunAsync(priority, callback) |
DispatcherQueue.TryEnqueue(priority, callback) |
Dispatcher.HasThreadAccess |
DispatcherQueue.HasThreadAccess |
CoreDispatcher.ProcessEvents() |
无等效项 — 重构异步代码 |
CoreWindow.GetForCurrentThread() |
不可用 — 使用 DispatcherQueue.GetForCurrentThread() |
关键区别:UWP 使用 ASTA(应用程序 STA)并内置重入阻塞。WinUI 3 使用标准 STA,无此保护。当异步代码泵送消息时,请注意重入问题。
后台任务迁移
// ❌ 错误 — UWP IBackgroundTask
public sealed class MyTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance) { }
}
// ✅ 正确 — Windows App SDK AppLifecycle
using Microsoft.Windows.AppLifecycle;
// 注册激活
var args = AppInstance.GetCurrent().GetActivatedEventArgs();
if (args.Kind == ExtendedActivationKind.AppNotification)
{
// 处理后台激活
}
应用设置迁移
| 场景 | 打包应用 | 未打包应用 |
|---|---|---|
| 简单设置 | ApplicationData.Current.LocalSettings |
LocalApplicationData 中的 JSON 文件 |
| 本地文件存储 | ApplicationData.Current.LocalFolder |
Environment.GetFolderPath(SpecialFolder.LocalApplicationData) |
GetForCurrentView() 替换
所有 GetForCurrentView() 模式在 WinUI 3 桌面应用中不可用:
| UWP API | WinUI 3 替换 |
|---|---|
UIViewSettings.GetForCurrentView() |
使用 AppWindow 属性 |
ApplicationView.GetForCurrentView() |
AppWindow.GetFromWindowId(windowId) |
DisplayInformation.GetForCurrentView() |
Win32 GetDpiForWindow() 或 XamlRoot.RasterizationScale |
CoreApplication.GetCurrentView() |
不可用 — 手动跟踪窗口 |
SystemNavigationManager.GetForCurrentView() |
直接在 NavigationView 中处理后退导航 |
测试迁移
UWP 单元测试项目不适用于 WinUI 3。您必须迁移到 WinUI 3 测试项目模板。
| UWP | WinUI 3 |
|---|---|
| 单元测试应用(通用 Windows) | 单元测试应用(桌面版 WinUI) |
| 使用 UWP 类型的标准 MSTest 项目 | 必须使用 WinUI 测试应用以支持 XAML 运行时 |
所有测试使用 [TestMethod] |
逻辑测试使用 [TestMethod],XAML/UI 测试使用 [UITestMethod] |
| 类库(通用 Windows) | 类库(桌面版 WinUI) |
// ✅ WinUI 3 单元测试 — 任何 XAML 交互使用 [UITestMethod]
[UITestMethod]
public void TestMyControl()
{
var control = new MyLibrary.MyUserControl();
Assert.AreEqual(expected, control.MyProperty);
}
关键: [UITestMethod] 属性告诉测试运行器在 XAML UI 线程上执行测试,这对于实例化任何 Microsoft.UI.Xaml 类型是必需的。
迁移清单
- [ ] 将所有
Windows.UI.Xaml.*using 指令替换为Microsoft.UI.Xaml.* - [ ] 将
Windows.UI.Colors替换为Microsoft.UI.Colors - [ ] 将
CoreDispatcher.RunAsync替换为DispatcherQueue.TryEnqueue - [ ] 将
Window.Current替换为App.MainWindow静态属性 - [ ] 为所有
ContentDialog实例添加XamlRoot - [ ] 使用
InitializeWithWindow.Initialize(picker, hwnd)初始化所有选择器 - [ ] 将
MessageDialog替换为ContentDialog - [ ] 将
ApplicationView/CoreWindow替换为AppWindow - [ ] 将
CoreApplicationViewTitleBar替换为AppWindowTitleBar - [ ] 将所有
GetForCurrentView()调用替换为AppWindow等效项 - [ ] 更新共享和打印管理器的互操作
- [ ] 将
IBackgroundTask替换为AppLifecycle激活 - [ ] 更新项目文件:TFM 为
net10.0-windows10.0.22621.0,添加<UseWinUI>true</UseWinUI> - [ ] 将单元测试迁移到**单元测试应用(桌面版 WinUI)**项目;XAML 测试使用
[UITestMethod] - [ ] 测试打包和未打包两种配置






