[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1
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 包
解决从旧格式的 csproj 迁移到新格式的 csproj 格式 AssemblyInfo 文件值重复问题
WPF 讲讲 Microsoft.NET.Sdk.WindowsDesktop 的原理
[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1的更多相关文章
- vs2017 C# ActiveX浏览器插件 创建 发布 C# windows窗体控件库(.NET Framework)注意事项
vs2017需要安装插 插件下载地址:https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.Micro ...
- WindowsXamlHost:在 WPF 中使用 UWP 控件库中的控件
在 WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit) 一文中,我们说到了在 WPF 中引入简单的 UWP 控件以及相关的注意事项 ...
- 《Dotnet9》系列-开源C# Winform控件库1《HZHControls》强力推荐
大家好,我是Dotnet9小编,一个从事dotnet开发8年+的程序员.我最近在写dotnet分享文章,希望能让更多人看到dotnet的发展,了解更多dotnet技术,帮助dotnet程序员应用dot ...
- 我的WPF控件库——KAN.WPF.XCtrl(141105)
自己开发的WPF控件库,只是初版,有扩展的Button,TextBox,Window.详细参见前几篇博文. WPF自定义控件(一)——Button:http://www.cnblogs.com/Qin ...
- WPF 控件库——仿制Windows10的进度条
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- WPF 控件库——仿制Chrome的ColorPicker
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- WPF 控件库——轮播控件
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- WPF 控件库——带有惯性的ScrollViewer
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- WPF 控件库——可拖动选项卡的TabControl
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
随机推荐
- 进阶之路 | 奇妙的Thread之旅
前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 需要已经具备的知识: Thread的基本概念及使用 AsyncTask的基本概念及使用 学习清单: 线程概述 ...
- 单片机基础——使用GPIO扫描检测按键
1. 准备工作 硬件准备 开发板首先需要准备一个小熊派IoT开发板,并通过USB线与电脑连接. 软件准备 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码,可参考MDK安装教程 ...
- 爬取疫情数据,以django+pyecharts实现数据可视化web网页
在家呆着也是呆着,不如做点什么消磨时间呗~ 试试用django+pyecharts实现疫情数据可视化web页面 这里要爬疫情数据 来自丁香园.搜狗及百度的疫情实时动态展示页 先看看劳动成果: 导航栏: ...
- zabbix图表出现中文乱码
搭建完成Zabbix监控服务器之后,切换到中文语言,图表展示出现乱码,如图所示 按照网上流传的上传windows下的字体的方法,还是不行,最后发现是PHP编译时的问题: php在编译时开启了-enab ...
- ggplot2(7) 定位
7.1 简介 位置调整:调整每个图层中出现重叠的对象的位置,对条形图和其他有组距的图形非常有用: 位置标度:控制数据到图形中位置的映射,常用的是对数变换: 分面:先将数据集划分为多个子集,然后将每个子 ...
- C++ Dll中导出一个类
//定义一个头文件,创建MyObject.h的头文件 并打印如下代码 #ifndef _MY_OBJECT_H #define _MY_OBJECT_H #ifndef MYDLL_EXPORTS # ...
- 将xml处理为json对象数组
function xmlStr2js(xmlStr) { var tagNames = xmlStr.match(/<\w+>/g) tagNames = deWeightTagNames ...
- 5分钟使用NetModular 完成通讯录 App 开发
原版连接:https://www.cnblogs.com/shanyou/p/12520894.html NetModular(后文简称NM)是 OLDLI 堪称艺术品级的应用开发框架,它基于经典领域 ...
- Android网络开发
1. WebView用法 ①布局文件新建一个WebView,特别注意线性布局和控件的宽高都要匹配父控件 <LinearLayout xmlns:android="http://sche ...
- 使用C#+EmguCV处理图像入门(图像读取_显示_保存)二
上个随笔已经介绍EmguCV的一些常用库和程序安装以及环境变量的配置,这次写的是如何使用这个类库对图像进行操作. EmguCV图像处理系统组成(个人见解): 图像的基本操作: 贴个代码: using ...