欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

程序员文章站 2022-05-28 23:07:59
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”:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

在结果窗口选择“open report”:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

结果将以excel的方式显示,像这种小项目一般不会出现什么问题,图个安心:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

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”:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

在弹出的对话框会列出*的依赖项和传递的依赖项,还会询问是否将后者升级到*依赖项,这个项目无需做任何改变,直接点击“确定”:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

迁移完成后会得到一个报告:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

打开kino.toolkit.wpf.csproj,会发现少了些东西,但多了下面这段,这段就是经过精简的nuget引用,在“管理nuget程序包”的页面也可以看到已安装的nuget变少了:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

完成这一步后还原nuget包,该升级的升级,运行下确认升级没有出错,然后进行下一步。

4. 迁移csproj项目文件

接下来需要迁移csproj项目文件到新的sdk-style格式,不过在那以前好歹先确保自己已经安装了.net core 3.1 sdk,随便新建一个wpf (.net core)项目,这里我选择了自定义控件库项目:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

生成的项目的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包重新编译等一系列操作都完成后,可以见到项目已经完成迁移了:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

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内引用这个项目,具体可见命名空间这一段内容。

然后重新填一填应用程序和打包信息,可以看到项目文件中多了不少内容:

[WPF]是时候将WPF控件库从.Net Framework升级到.NET Core 3.1

<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 包