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 類型所必需的。
遷移檢查清單
- [ ] 將所有
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等效項目 - [ ] 更新共用與列印管理員的 Interop
- [ ] 將
IBackgroundTask取代為AppLifecycle啟用 - [ ] 更新專案檔:TFM 設為
net10.0-windows10.0.22621.0,新增<UseWinUI>true</UseWinUI> - [ ] 將單元測試遷移至單元測試應用程式 (桌面版 WinUI) 專案;XAML 測試使用
[UITestMethod] - [ ] 測試封裝與未封裝兩種設定






