商店踩坑 #4:.NET 裁剪把 WinUI 3 的綁定裁沒了
2026-05-31
Tags: Windows · Microsoft Store · 商店踩坑
這是很早期就遇到的問題,最近寫踩坑系列翻郵件時翻到了一封很久之前的拒信——希望這篇記錄能給剛接觸 WinUI 3 / .NET 發佈流程的開發者做個參考。
發生了什麼
我的一款 WinUI 3 應用程式提交了 Microsoft Store 認證。認證報告回來了:
Status: Attention needed
10.1.2.10 Functionality
Unusable Feature: "Download to local cache", "Open File" - The product fails to download copied items to local cache and "Open File" button in the product is not usable
等等——我在本地明明測試過,「下載到本地快取」和「開啟檔案」都是正常工作的。為什麼微軟的測試機上就不行了?
排查
最可疑的區別是:我在本地用的是 Debug 建置,而提交到商店的是 Release 建置。檢查 .csproj 檔案,發現 Debug 和 Release 設定之間有一個關鍵差異:
<!-- Debug -->
<PublishTrimmed>False</PublishTrimmed>
<!-- Release -->
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>Release 建置開啟了 .NET 裁剪(Trimming)。
什麼是 .NET 裁剪
.NET 裁剪是 .NET SDK 提供的一項最佳化功能。發行應用程式時,裁剪器會透過靜態分析找出程式碼中從未被直接參考的組件、型別和方法,然後把它們刪除,從而減小應用程式體積。
問題在於:裁剪器只看得到靜態參考。如果你的程式碼透過反射在執行時呼叫某個型別,而編譯時沒有任何靜態參考指向它,裁剪器就會認為這個型別「沒被用到」,然後把它裁掉。
為什麼 WinUI 3 特別容易中招
WinUI 3 及其底層的 WinRT 互操作大量依賴反射和動態特性。傳統 {Binding}、值轉換器以及 WinRT 元件互操作中的元資料反射,都會產生裁剪器無法透過靜態分析追蹤的執行階段呼叫。當裁剪器把綁定需要的資料模型、命令、轉換器等型別統統當作「未使用」刪掉後,到了執行階段,UI 上的按鈕、文字更新等功能就靜默失效了——不會報錯,不會當機,就是單純不工作。
解決方案
最直接的辦法:在 .csproj 裡關閉裁剪:
- <PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
+ <PublishTrimmed>False</PublishTrimmed>重新打包提交,認證通過。
如果你確實需要裁剪來減小套件體積,也可以透過以下方式相容:
- 在需要的型別上標註
[DynamicDependency]或[DynamicallyAccessedMembers]特性,告訴裁剪器保留它們 - 在
.csproj中設定<TrimmerRootAssembly>保留整個組件
但對於大多數 WinUI 3 應用程式來說,直接關閉裁剪是最省心的選擇。
小結
- .NET 裁剪會刪除它認為「未使用」的程式碼,但無法識別反射呼叫
- WinUI 3 的資料綁定依賴反射,很容易被誤裁
- 如果 WinUI 3 應用程式在商店認證時出現「功能不可用」但你在本地測試正常,第一個排查的就是裁剪
- Debug 建置預設不裁剪,Release 建置可能開啟裁剪——提交商店前務必測試 Release/Publish 建置
- 接下來我們會寫一篇文章,給出一些提交商店前的測試建議,敬請期待
本文屬於商店踩坑系列。