winui3-migration-guide

winui3-migration-guide

熱門

UWP 轉換至 WinUI 3 的遷移參考指南。對應舊版 UWP API 至正確的 Windows App SDK 等效項目,並附有前後程式碼片段。涵蓋命名空間變更、執行緒 (CoreDispatcher 改為 DispatcherQueue)、視窗 (CoreWindow 改為 AppWindow)、對話方塊、選擇器、共用、列印、背景工作,以及最常見的 Copilot 程式碼產生錯誤。

3.7萬星標
4593分支
更新於 2026/7/17
SKILL.md
readonlyread-only
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

// ❌ 錯誤 — WinUI 3 中沒有 CoreDispatcher
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    StatusText.Text = "完成";
});
// ✅ 正確 — 使用 DispatcherQueue
DispatcherQueue.TryEnqueue(() =>
{
    StatusText.Text = "完成";
});

// 指定優先順序:
DispatcherQueue.TryEnqueue(DispatcherQueuePriority.High, () =>
{
    ProgressBar.Value = 100;
});

視窗遷移

視窗參考

// ❌ 錯誤 — WinUI 3 中沒有 Window.Current
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 類型所必需的。


遷移檢查清單

  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. [ ] 更新共用與列印管理員的 Interop
  12. [ ] 將 IBackgroundTask 取代為 AppLifecycle 啟用
  13. [ ] 更新專案檔:TFM 設為 net10.0-windows10.0.22621.0,新增 <UseWinUI>true</UseWinUI>
  14. [ ] 將單元測試遷移至單元測試應用程式 (桌面版 WinUI) 專案;XAML 測試使用 [UITestMethod]
  15. [ ] 測試封裝與未封裝兩種設定