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

来源:https://www.cnblogs.com/dino623/archive/2020/04/08/Migrating_WPF_Control_Library_to_NET_Core.html
-Advertisement-
Play Games

1. 升級到Core的好處 去年中我曾考慮將我的控制項庫項目 "Kino.Toolkit.Wpf" 升級到.NET Core,不過很快放棄了,因為當時.NET Core是預覽版,編譯WPF還需要使用最新的Visual Studio 2019,這樣作為一個教學項目不夠友好。到了今天.NET Core 3 ...


1. 升級到Core的好處

去年中我曾考慮將我的控制項庫項目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升級到core 3.1以作比較。需要註意的是,WPF控制項庫的升級和其它.NET項目的升級有一點出入,這篇文章的升級方式不一定適合其它.NET Core項目。

2. .NET 可移植性分析

在升級前,保險起見需要使用.NET 可移植性分析器分析項目在目標.NET平臺上的可移植性。安裝.NET Portability Analyzer這個Visual Studio的擴展後在Visual Studio的解決方案資源管理器視窗選中要分析的項目,右鍵選擇“Analyze Project Portability”:

在結果視窗選擇“Open Report”:

結果將以Excel的方式顯示,像這種小項目一般不會出現什麼問題,圖個安心:

3. 遷移到 PackageReference NuGet 引用

引用了Nuget包的舊.NET Framework項目會將引用的Nuget信息記錄在packages.config文件中,例如在示例的項目中,這個文件的內容如下:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.CodeAnalysis.FxCopAnalyzers" version="2.9.8" targetFramework="net45" developmentDependency="true" />
  <package id="Microsoft.CodeAnalysis.VersionCheckAnalyzer" version="2.9.8" targetFramework="net45" developmentDependency="true" />
  <package id="Microsoft.CodeQuality.Analyzers" version="2.9.8" targetFramework="net45" developmentDependency="true" />
  <package id="Microsoft.NetCore.Analyzers" version="2.9.8" targetFramework="net45" developmentDependency="true" />
  <package id="Microsoft.NetFramework.Analyzers" version="2.9.8" targetFramework="net45" developmentDependency="true" />
  <package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.19" targetFramework="net45" />
</packages>

新的SDK-Style項目文件使用PackageReference節點記錄Nuget的引用信息,這樣做的好處包括精簡內容與以及不再需要額外的packages.config文件,所以我們必須將packages.config遷移到 PackageReference。要遷移到PackageReference,先儘可能升級引用的Nuget包,然後選中項目中的packages.config,在右鍵菜單中選中“將 packages.config 遷移到 PackageReference”:

在彈出的對話框會列出頂級的依賴項和傳遞的依賴項,還會詢問是否將後者升級到頂級依賴項,這個項目無需做任何改變,直接點擊“確定”:

遷移完成後會得到一個報告:

打開Kino.Toolkit.Wpf.csproj,會發現少了些東西,但多了下麵這段,這段就是經過精簡的Nuget引用,在“管理Nuget程式包”的頁面也可以看到已安裝的Nuget變少了:

完成這一步後還原Nuget包,該升級的升級,運行下確認升級沒有出錯,然後進行下一步。

4. 遷移csproj項目文件

接下來需要遷移csproj項目文件到新的SDK-Style格式,不過在那以前好歹先確保自己已經安裝了.NET Core 3.1 SDK,隨便新建一個WPF (.NET Core)項目,這裡我選擇了自定義控制項庫項目:

生成的項目的csproj項目文件如下:

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

</Project>

其中SDK 是一組可生成 .NET Core 代碼的 MSBuild 任務和目標,Sdk="Microsoft.NET.Sdk.WindowsDesktop"標識這是一個.NET Core的WinForms或WPF項目。

PropertyGroup這一節表明這是個.NET Core 3.1項目,並使用WPF。如果是應用程式項目的話還需要<OutputType>WinExe</OutputType>,因為這是個類庫項目所以缺少了這一節。

為了可以支持多個框架,需要將<TargetFramework>這一節改為下麵內容,註意TargetFramework變為TargetFrameworks,因為從單一框架變成多個框架。

<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>

現在可以把這些內容複製到Kino.Toolkit.Wpf.csproj,加上前面提到的<PackageReference>節點的內容,完整內容如下:

  <PropertyGroup>
    <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
      <Version>2.9.8</Version>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.Xaml.Behaviors.Wpf">
      <Version>1.1.19</Version>
    </PackageReference>
  </ItemGroup>
 
</Project>

重新載入項目,還原Nuget包重新編譯等一系列操作都完成後,可以見到項目已經完成遷移了:

5. 處理其它問題

遷移項目文件後會有一些問題,首先是以前從項目中排除的文件又包含在項目里了,畢竟以前那麼複雜的項目文件可不是吃素的,這麼簡單粗暴遷移過來總會丟一些內容。重新將他們從項目中排除,項目文件多了以下這些內容,以表明這些文件都是多餘的(如果文件真是多餘的也可以直接刪掉):

<ItemGroup>
  <Compile Remove="Class1.cs" />
  <Compile Remove="SkeletonScreen\DispatcherContainer.cs" />
</ItemGroup>
<ItemGroup>
  <None Remove="ClassDiagram1.cd" />
</ItemGroup>

AssemblyInfo.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內引用這個項目,具體可見命名空間這一段內容。

然後重新填一填應用程式和打包信息,可以看到項目文件中多了不少內容:

<PropertyGroup>
  <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
  <UseWPF>true</UseWPF>
  <ApplicationIcon>Assets\Images\kino.ico</ApplicationIcon>
  <Version>1.6.0</Version>
  <Copyright>Copyright ©  2019</Copyright>
  <PackageLicenseExpression>https://raw.githubusercontent.com/DinoChan/Kino.Toolkit.Wpf/master/LICENSE</PackageLicenseExpression>
  <PackageProjectUrl>https://github.com/DinoChan/Kino.Toolkit.Wpf</PackageProjectUrl>
  <PackageIcon>Logo.png</PackageIcon>
  <RepositoryUrl>https://github.com/DinoChan/Kino.Toolkit.Wpf</RepositoryUrl>
<PropertyGroup>
  <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
  <UseWPF>true</UseWPF>
  <ApplicationIcon>Assets\Images\kino.ico</ApplicationIcon>
  <Version>1.6.0</Version>
  <Copyright>Copyright ©  2019</Copyright>
  <PackageLicenseExpression></PackageLicenseExpression>
  <PackageProjectUrl>https://github.com/DinoChan/Kino.Toolkit.Wpf</PackageProjectUrl>
  <PackageIcon>Logo.png</PackageIcon>
  <RepositoryUrl>https://github.com/DinoChan/Kino.Toolkit.Wpf</RepositoryUrl>
  <PackageTags>WPF Control Toolkit Xaml</PackageTags>
  <Description>A set of wpf toolkit.</Description>
  <NeutralLanguage>en-US</NeutralLanguage>
</PropertyGroup>

具體的打包成Nuget的過程可以參考林德熙的這篇文章:

VisualStudio 使用新項目格式快速打出 Nuget 包

6. 結語

實際上WPF項目要遷移到.NET Core會複雜很多,目前我也只是在控制項庫上嘗試。但換成新SDK-Style項目格式沒什麼壞處,可以放手一拼(只要不我讓我負責任)。

有些項目可能還需要安裝Microsoft.Windows.Compatibility,更多的信息請看下麵給出的參考鏈接。

7. 參考

Migrating WPF Apps to .NET Core 3.0 - WPF _ Microsoft Docs

.NET Core 的 csproj 格式的新增內容 - .NET Core CLI _ Microsoft Docs

從 .NET Framework 移植到 .NET Core - .NET Core _ Microsoft Docs

將 Contoso Expenses 應用遷移到 .NET Core 3 _ Microsoft Docs

.NET 可移植性分析器 - .NET _ Microsoft Docs

將傳統 WPF 程式遷移到 DotNetCore 3.0 - hippieZhou - 博客園

將基於 .NET Framework 的 WPF 項目遷移到基於 .NET Core 3 - walterlv

VisualStudio 使用新項目格式快速打出 Nuget 包

從以前的項目格式遷移到 VS2017 新項目格式

解決從舊格式的 csproj 遷移到新格式的 csproj 格式 AssemblyInfo 文件值重覆問題

WPF 講講 Microsoft.NET.Sdk.WindowsDesktop 的原理


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 問題:在webserver中接收xml參數出現了問題,提示System.Xml.XmlException: 分析 EntityName 時出錯。 webserver中的方法是前同事寫的,調用的方法和傳的參數基本都差不多,代碼也是沒有問題的,後來在百度的時候找到了問題所在: 問題就出現在xml里,因為 ...
  • 歷史原因,筆者所在公司的項目目前還在使用 .NET CORE 2.2版本,在所有業務應用升級完成服務註冊發現之後,最後剩下 Ocelot 網關服務升級。在升級過程中,遇到一些問題,記錄此文,以便有相同情況的同學參考。 1. Ocelot 升級服務發現 "根據官方文檔" ,通過簡單的添加配置,既可以將 ...
  • 項目中可能會遇到重寫控制項的情況,特此記錄下: 1 <Window x:Class="WpfApp6.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://sc ...
  • 創建一個簡單用戶控制項是開始自定義控制項的好方法。本章主要介紹創建一個基本的顏色拾取器。接下來分析如何將這個控制項分解成功能更強大的基於模板的控制項。 創建基本的顏色拾取器很容易。然而,創建自定義顏色拾取器仍是有價值的聯繫,因為這不僅演示了構建控制項的各種重要概念,而且提供了一個實用的功能。 可為顏色拾取器創 ...
  • 需求很簡單,就是文本框想要個placeholder的效果,中文的時候顯示“姓名”,英文的時候顯示“Name”,於是有了以下代碼: 然後,動態切換成英文資源的時候,發現他還是中文的,暈。後來改成以下代碼就OK了,不知和解? ...
  • public static int AddBook(BookInfo bookInfo) { using (BookDBContext dbContext = new BookDBContext()) { dbContext.BookInfo.Add(bookInfo); return (dbCon ...
  • /// <summary> /// 修改 /// </summary> /// <param name="bookInfo"></param> /// <returns></returns> public static bool Update(BookInfo bookInfo) { using ( ...
  • 必應每天都會更換背景圖片,都非常漂亮,有的時候還十分驚艷,同時還會根據每個地區的特色不同應用不同的圖片。 下麵用c 抓取必應每天的背景圖片,並實現桌面壁紙的每天自動切換 實現思路 1.通過獲取“必應”網頁背景圖片URL 2.下載圖片到本地 3.設置這個圖片為壁紙 4.每日自動切換壁紙 1.創建項目文 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...