1. 開發了一個摸魚 app
我做了一個簡單的 app:摸魚。


如上圖所示,這個 app 就只有一個按鈕,點擊後假裝開始 windows update,然後用戶就可以光明正大地摸魚了。
不要小看摸魚,所有天才的點子都不是敲鍵盤時激發的。在工作遇到阻滯時,越是投入工作越是找不到解決方案,這時候把目光從屏幕挪開,說不定在一邊洗澡一邊玩著小黃鴨時,一邊發呆一邊看著窗外時,一邊睡覺一邊扣肚子時,解決問題的靈感突然就掉進了腦海里。
所以我恬不知恥地將這個 app 發布到了 高效工作 分類,微軟還通過了,現在可以在這裡下載到這個應用:
https://www.microsoft.com/zh-cn/p/loaf-a-winui3-app/9ndj3q12nrrm

當然,如標題所說,這是個 winui 3 app。
2. 什麼是 winui 3

winui 3 是隨 windows app sdk 提供的適用於 windows 桌面應用程式和 uwp 應用程式的本機用戶體驗 (ux) 框架。簡單來說,winui 3 將 uwp 的 ui 層分離出來給 win32 windows app 使用。為了更好地理解 winui 3 可以參考下面的連結:
- Windows UI 库 (WinUI) - Windows apps
- Windows UI 库 (WinUI) 3 - Windows apps
- 通过 Windows 应用 SDK 生成桌面 Windows 应用 - Windows apps
- Windows 应用 SDK 的稳定通道发行说明 - Windows apps
- microsoftmicrosoft-ui-xaml Windows UI Library_ the latest Windows 10 native controls and Fluent styles for your applications
- microsoft-ui-xaml_roadmap
- WinUI 3 试玩报告
- WinUI 3 Preview 3 发布了,再一次试试它的性能
經過長久的等待,最近,winui 3 好像悄悄地發布了正式版。既沒有大型的宣傳,又沒有集成在剛剛發布的 visual studio 2022 里,甚至沒看到像樣的郵件或新聞、博客,查文檔的話它好像和 windows app sdk 一起發布了,總之現在 winui 3 的 1.0 版本能用了。在把玩了一番後我覺得暫時不能把自己的 app 遷移到 winui 3,雖然我已經期待了很久很久。因為不能對現有應用動手,又為了更深入嘗試 winui 3,我做了“摸魚”這個小應用。
3. 開發過程
下面來說說開發過程。總體來說挺好玩,但也有很多挑戰。
首先,如果要使用 Visual Studio 2022 开发 WinUI 3 的 C# App,需要下载 Visual Studio 2022 的扩展:WindowsAppSDK.Cs.Extension.Dev17.Standalone.vsix。安装扩展后才可以创建 WinUI 3 项目。

c++ 或 visual studio 2019 的擴展可以在以下文檔找到各自的下載連結:
Windows 应用 SDK 的稳定通道发行说明 - Windows apps
創建好項目後就會發現 winui 3 沒有設計視圖(以後應該也不會有),所以這時候最好還是再創建一個 uwp 項目,在 uwp 項目中把 xaml 設計好再複製到 winui 3 項目。
迁移过程中需要将大部分 Windows.* 命名空间替换成 Microsoft.*。不过 Win2D 里还在用 Windows.* 命名空间,所以搞得有些混乱。
然后就是引用各种包,微软自己管理的 UWP 最常用的包大致上都有对应的 WinUI 版本,例如 Microsoft.Toolkit.Uwp.UI 替换为 CommunityToolkit.WinUI.UI,而 Win2D.uwp 替换为 Microsoft.Graphics.Win2D。
uwp 大部分開發經驗都可以用在 winui 3 上,在 摸魚 這個小 app 里遇到最大的問題是 window 管理。可能 winui 3 的 window api 還沒想好,導致連修改標題都很麻煩,需要用到好幾行代碼:
namespace SampleApp
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : Window
{
private AppWindow m_appWindow;
public MainWindow()
{
this.InitializeComponent();
// Get the AppWindow for our XAML Window
m_appWindow = GetAppWindowForCurrentWindow();
if (m_appWindow != null)
{
// You now have an AppWindow object and can call its methods to manipulate the window.
// Just to do something here, let's change the title of the window...
m_appWindow.Title = "WinUI ❤️ AppWindow";
}
}
private AppWindow GetAppWindowForCurrentWindow()
{
IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
WindowId myWndId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd);
return AppWindow.GetFromWindowId(myWndId);
}
}
}
進入全屏的代碼也和 uwp 不一樣:
///进入全屏
m_appWindow.SetPresenter(AppWindowPresenterKind.FullScreen);
///退出全屏
m_appWindow.SetPresenter(AppWindowPresenterKind.Default);
而且全屏和 UWP 还不一样,没法按 Esc 键退出全屏,也没有了屏幕顶部隐藏的标题栏。所以要自己捕获全局的 Esc 键事件再调用代码退出全屏(至于平板状态怎么退出全屏我就不知道了)。
還有一點,winui 3 和 uwp 的樣式有些不一樣,例如 progressring 的樣式就不是 windows 8 以來那個幾個點轉圈圈的樣式。幸好可以把 uwp 的 style 複製過來,只需簡單修改一下。
虽然开发过程遇到很多问题,对这个小 App 来说还算轻松愉快。有趣的是,当遇到 WinUI 3 没提供想要的 API 的时候可以直接调用 Win32 API 实现需求。更有趣的是,这些 Win32 API 有些有效,有些无效。
所有代碼完成後,最後一步是發布到商店,幸好發布流程和 uwp 的基本一致,現在已經可以在商店下載這款 app。
4. 遇到的問題
沒有設計視圖,這是個很嚴重的問題。我自己倒是還可以接受,因為起碼還有熱重載可用,但對入門不友好。
文档混乱,几乎所有 UWP 和 Windows App SDK 的文档合并了,这就要命了,真的要命,例如 WinUI 3 的文档有指向 Mica 的导航,明明 WinUI 3 都不支持 Mica。现在在 https://docs.microsoft.com/en-us/windows/apps/ 页面里甚至找不到 UWP 的入口,总之无论 UWP 还是 Windows App SDK 的文档都一片混沌。
demo 沒用,給我 uwp 的 demo 就算了,連 windows 8 的 demo 都給我端上來就過分了。
windows app sdk 這個名字本身就不好,所有引擎搜出來一大堆 windows 的東西,但不是 windows app sdk 的。
沒有 background acrylic 和 revealboraderbrush,win2d 也缺了 canvasanimatedcontrol,這些東西的缺失提高了從 uwp 遷移到 winui 3 的難度。
從開發到發布一路上遇上各種一言難盡的 bug 和小問題。
5. 最後
我記得當年 winforms、wpf、silverlight 的入門都相當輕鬆,後面微軟的各個 ui 越來越難,而 winui 3 更是最難的一個。比起 uwp,winui 3 本應該有巨大的優勢,但現在我建議暫時還是再等等新版本。玩玩小應用可以,生產環境要謹慎。
倒是 winui 2 好像越來越好玩,或者我們可以一邊玩 winui 2 一邊等 winui 3 的新版本。
6. 源碼
https://github.com/DinoChan/Loaf
作者:dino.c
出處:https://www.cnblogs.com/dino623/p/developing_an_app_with_winui3.html
版權:本文採用“cc by 4.0”知識共享許可協議進行許可。