🚀 快速安装

复制以下命令并运行,立即安装此 Skill:

npx skills add https://github.com/github/awesome-copilot --skill winui3-migration-guide

💡 提示:需要 Node.js 和 NPM

WinUI 3 迁移指南

在将 UWP 应用迁移到 WinUI 3 / Windows 应用 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 (用于调度器)

Copilot 最常见的 3 个错误

1. 未设置 XamlRoot 的 ContentDialog

// ❌ 错误 — 在 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 应用 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(预期值, control.MyProperty);
}

关键: [UITestMethod] 属性告诉测试运行程序在 XAML UI 线程上执行测试,这是实例化任何 Microsoft.UI.Xaml 类型所必需的。


迁移清单

  1. 将所有 Windows.UI.Xaml.* using 指令替换为 Microsoft.UI.Xaml.*
  2. Windows.UI.Colors 替换为 Microsoft.UI.Colors
  3. CoreDispatcher.RunAsync 替换为 DispatcherQueue.TryEnqueue
  4. Window.Current 替换为静态属性 App.MainWindow
  5. 为所有 ContentDialog 实例添加 XamlRoot
  6. 使用 InitializeWithWindow.Initialize(picker, hwnd) 初始化所有选择器
  7. MessageDialog 替换为 ContentDialog
  8. ApplicationView/CoreWindow 替换为 AppWindow
  9. CoreApplicationViewTitleBar 替换为 AppWindowTitleBar
  10. 将所有 GetForCurrentView() 调用替换为 AppWindow 等效项
  11. 更新共享和打印管理器的互操作
  12. IBackgroundTask 替换为 AppLifecycle 激活
  13. 更新项目文件:TFM 为 net10.0-windows10.0.22621.0,添加 <UseWinUI>true</UseWinUI>
  14. 将单元测试迁移到 单元测试应用(桌面版 WinUI) 项目;XAML 测试使用 [UITestMethod]
  15. 测试打包和未打包两种配置

📄 原始文档

完整文档(英文):

https://skills.sh/github/awesome-copilot/winui3-migration-guide

💡 提示:点击上方链接查看 skills.sh 原始英文文档,方便对照翻译。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。