1. 程式人生 > >[WPF]是時候將WPF控制元件庫從.Net Framework升級到.NET Core 3.1

[WPF]是時候將WPF控制元件庫從.Net Framework升級到.NET Core 3.1

## 1. 升級到Core的好處 去年中我曾考慮將我的控制元件庫專案[Kino.Toolkit.Wpf](https://github.com/DinoChan/Kino.Toolkit.Wpf)升級到.NET Core,不過很快放棄了,因為當時.NET Core是預覽版,編譯WPF還需要使用最新的Visual Studio 2019,這樣作為一個教學專案不夠友好。到了今天.NET Core 3.1都出來了,已經正式支援WPF和Winform,Visual Studio 2019也已經普及,我覺得應該是時候將我的控制元件庫升級到.NET Core。那麼現在是WPF正式遷移到.NET Core的好時機嗎?我認為還不是,把一個成熟的WPF程式遷移到.NET Core風險任然較大,而且不見得有多少好處。但對各種WPF類庫/控制元件庫來說情況又不一樣了,為了可以滿足更多的使用者,讓控制元件庫可以同時支援.NET Framework和.NET Core十分重要;而且通常類庫對其它元件的依賴較少,升級的風險沒那麼大。所以要玩.NET Core的WPF,從類庫/控制元件庫開始是一個好的選擇。 具體來說,讓WPF控制元件庫升級到.NET Core具體來說有以下的好處: * 巨大的時髦值,最近WPF開發時髦值很低,.NET Core是我們為數不多可以蹭到時髦值、面向時髦值程式設計的機會。 * 新的csproj檔案,順便升級到新的SDK-style csproj檔案有很多好處,包括更簡潔可讀的檔案,新的NuGet引用方式,可以指定多個開發框架等。 * 更方便打包Nuget。 升級到.NET Core 3.1有以下步驟: * 分析可移植性 * 遷移到 NuGet 引用 * 遷移csproj專案檔案 這篇文章我會以我的Kino.Toolkit.Wpf專案作為示例,master分支不升級,而[core](https://github.com/DinoChan/Kino.Toolkit.Wpf/tree/core)升級到core 3.1以作比較。需要注意的是,WPF控制元件庫的升級和其它.NET專案的升級有一點出入,這篇文章的升級方式不一定適合其它.NET Core專案。 ## 2. .NET 可移植性分析 在升級前,保險起見需要使用[.NET 可移植性分析器](https://docs.microsoft.com/zh-cn/dotnet/standard/analyzers/portability-analyzer)分析專案在目標.NET平臺上的可移植性。安裝[.NET Portability Analyzer](https://marketplace.visualstudio.com/items?itemName=ConnieYau.NETPortabilityAnalyzer)這個Visual Studio的擴充套件後在Visual Studio的`解決方案資源管理器`視窗選中要分析的專案,右鍵選擇“Analyze Project Portability”: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125430958-648268647.png) 在結果視窗選擇“Open Report”: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125436726-240940576.png) 結果將以Excel的方式顯示,像這種小專案一般不會出現什麼問題,圖個安心: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125443522-354978865.png) ## 3. 遷移到 PackageReference NuGet 引用 引用了Nuget包的舊.NET Framework專案會將引用的Nuget資訊記錄在packages.config檔案中,例如在示例的專案中,這個檔案的內容如下: ``` XML
``` 新的SDK-Style專案檔案使用PackageReference節點記錄Nuget的引用資訊,這樣做的好處包括精簡內容與以及不再需要額外的packages.config檔案,所以我們必須將packages.config遷移到 PackageReference。要遷移到PackageReference,先儘可能升級引用的Nuget包,然後選中專案中的packages.config,在右鍵選單中選中“將 packages.config 遷移到 PackageReference”: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125507614-1063278661.png) 在彈出的對話方塊會列出頂級的依賴項和傳遞的依賴項,還會詢問是否將後者升級到頂級依賴項,這個專案無需做任何改變,直接點選“確定”: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125513913-1460944122.png) 遷移完成後會得到一個報告: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125519524-454656674.png) 開啟Kino.Toolkit.Wpf.csproj,會發現少了些東西,但多了下面這段,這段就是經過精簡的Nuget引用,在“管理Nuget程式包”的頁面也可以看到已安裝的Nuget變少了: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125905885-759686996.png) ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125528296-716329911.png) 完成這一步後還原Nuget包,該升級的升級,執行下確認升級沒有出錯,然後進行下一步。 ## 4. 遷移csproj專案檔案 接下來需要遷移csproj專案檔案到新的SDK-Style格式,不過在那以前好歹先確保自己已經安裝了[.NET Core 3.1 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.1),隨便新建一個WPF (.NET Core)專案,這裡我選擇了自定義控制元件庫專案: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125556209-840751523.png) 生成的專案的csproj專案檔案如下: ``` XML netcoreapp3.1
true
``` 其中SDK 是一組可生成 .NET Core 程式碼的 MSBuild 任務和目標,`Sdk="Microsoft.NET.Sdk.WindowsDesktop"`標識這是一個.NET Core的WinForms或WPF專案。 `PropertyGroup`這一節表明這是個.NET Core 3.1專案,並使用WPF。如果是應用程式專案的話還需要`WinExe`,因為這是個類庫專案所以缺少了這一節。 為了可以支援多個框架,需要將``這一節改為下面內容,注意`TargetFramework`變為`TargetFrameworks`,因為從單一框架變成多個框架。 ``` XML net462;netcoreapp3.1
``` 現在可以把這些內容複製到Kino.Toolkit.Wpf.csproj,加上前面提到的``節點的內容,完整內容如下: ``` XML net462;netcoreapp3.1 true 2.9.8 runtime; build; native; contentfiles; analyzers; buildtransitive all 1.1.19 ``` 重新載入專案,還原Nuget包重新編譯等一系列操作都完成後,可以見到專案已經完成遷移了: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125617331-1400712349.png) ## 5. 處理其它問題 遷移專案檔案後會有一些問題,首先是以前從專案中排除的檔案又包含在專案裡了,畢竟以前那麼複雜的專案檔案可不是吃素的,這麼簡單粗暴遷移過來總會丟一些內容。重新將他們從專案中排除,專案檔案多了以下這些內容,以表明這些檔案都是多餘的(如果檔案真是多餘的也可以直接刪掉): ``` XML ``` `AssemblyInfo.cs`這個檔案有很多版本號之類的資訊,現在都在專案檔案中宣告,所以這些資訊全都變得多餘,會引起編譯錯誤,全部刪掉只保留下面這些就好: ``` CS // [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] [assembly: ThemeInfo( ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly) ] [assembly: XmlnsPrefix("https://github.com/DinoChan/Kino.Toolkit.Wpf", "kino")] [assembly: XmlnsDefinition("https://github.com/DinoChan/Kino.Toolkit.Wpf", "Kino.Toolkit.Wpf")] [assembly: XmlnsDefinition("https://github.com/DinoChan/Kino.Toolkit.Wpf", "Kino.Toolkit.Wpf.Primitives")] ``` 其中`ThemeInfo`指示專案使用預設的`Themes\Generic.xaml`主題檔案,對WPF專案是必不可少。`XmlnsPrefix`等內容是為了方便在XAML內引用這個專案,具體可見[名稱空間](https://www.cnblogs.com/dino623/p/CustomControLibrary.html#2105837489)這一段內容。 然後重新填一填應用程式和打包資訊,可以看到專案檔案中多了不少內容: ![](https://img2020.cnblogs.com/blog/38937/202004/38937-20200405125630202-12034099.png) ``` XML net462;netcoreapp3.1 true Assets\Images\kino.ico 1.6.0 Copyright © 2019 https://raw.githubusercontent.com/DinoChan/Kino.Toolkit.Wpf/master/LICENSE https://github.com/DinoChan/Kino.Toolkit.Wpf Logo.png https://github.com/DinoChan/Kino.Toolkit.Wpf net462;netcoreapp3.1 true Assets\Images\kino.ico 1.6.0 Copyright © 2019 https://github.com/DinoChan/Kino.Toolkit.Wpf Logo.png https://github.com/DinoChan/Kino.Toolkit.Wpf WPF Control Toolkit Xaml A set of wpf toolkit. en-US ``` 具體的打包成Nuget的過程可以參考林德熙的這篇文章: [VisualStudio 使用新專案格式快速打出 Nuget 包 ](https://blog.lindexi.com/post/VisualStudio-%E4%BD%BF%E7%94%A8%E6%96%B0%E9%A1%B9%E7%9B%AE%E6%A0%BC%E5%BC%8F%E5%BF%AB%E9%80%9F%E6%89%93%E5%87%BA-Nuget-%E5%8C%85.html) ## 6. 結語 實際上WPF專案要遷移到.NET Core會複雜很多,目前我也只是在控制元件庫上嘗試。但換成新SDK-Style專案格式沒什麼壞處,可以放手一拼(只要不我讓我負責任)。 有些專案可能還需要安裝[Microsoft.Windows.Compatibility](https://www.nuget.org/packages/Microsoft.Windows.Compatibility),更多的資訊請看下面給出的參考連結。 ## 7. 參考 [Migrating WPF Apps to .NET Core 3.0 - WPF _ Microsoft Docs](https://docs.microsoft.com/zh-cn/dotnet/desktop-wpf/migration/convert-project-from-net-framework?view=vs-2019) [.NET Core 的 csproj 格式的新增內容 - .NET Core CLI _ Microsoft Docs](https://docs.microsoft.com/zh-cn/dotnet/core/tools/csproj) [從 .NET Framework 移植到 .NET Core - .NET Core _ Microsoft Docs](https://docs.microsoft.com/zh-cn/dotnet/core/porting/) [將 Contoso Expenses 應用遷移到 .NET Core 3 _ Microsoft Docs](https://docs.microsoft.com/zh-cn/windows/apps/desktop/modernize/modernize-wpf-tutorial-1) [.NET 可移植性分析器 - .NET _ Microsoft Docs](https://docs.microsoft.com/zh-cn/dotnet/standard/analyzers/portability-analyzer) [將傳統 WPF 程式遷移到 DotNetCore 3.0 - hippieZhou - 部落格園](https://www.cnblogs.com/hippieZhou/p/10661181.html) [將基於 .NET Framework 的 WPF 專案遷移到基於 .NET Core 3 - walterlv](https://walterlv.gitee.io/post/migrate-wpf-project-from-dotnet-framework-to-dotnet-core.html) [VisualStudio 使用新專案格式快速打出 Nuget 包](https://blog.lindexi.com/post/VisualStudio-%E4%BD%BF%E7%94%A8%E6%96%B0%E9%A1%B9%E7%9B%AE%E6%A0%BC%E5%BC%8F%E5%BF%AB%E9%80%9F%E6%89%93%E5%87%BA-Nuget-%E5%8C%85.html)