https://www.codeproject.com/Articles/5306711/Migrating-Windows-Apps-to-Windows-on-Arm-with-WPF
Gaston Verelst 2021年7月7日
在本文中,我们将了解如何将Windows.NET6WPF应用程序转换为WindowsonARM(WoA)应用程序。
这篇文章是一篇赞助文章。这些文章旨在为您提供我们认为对开发人员有用和有价值的产品和服务的信息。
将Windows.NET 6 WPF应用程序转换为Windows on Arm(WoA)应用程序需要设置开发环境并对应用程序进行一些更改,以使其在不使用仿真器的情况下在WoA上运行。
本文是"当前将Windows应用程序迁移到WoA的最佳实践"(https://www.codeproject.com/Articles/5293252/Todays-Best-Practices-for-Migrating-Windows-apps-t)的后续文章。
先决条件
在本文中,我们将把一个示例WPF应用程序移植到WoA环境中,使用C#作为我们的编程语言,因此需要一些C#和WPF/XAML的知识。
我们将使用Visual Studio 2019作为IDE。您应该知道如何创建项目、类和WPF表单。
介绍
在上一篇文章(https://www.codeproject.com/Articles/5293252/Todays-Best-Practices-for-Migrating-Windows-apps-t)中,我们看到了WoA如何执行几乎所有的.NET应用程序。它使用x86仿真层来执行没有为Aarch64处理器编译的程序。尽管仿真层尽可能地提高了性能,但我们注意到,为WoA本机编译的应用程序的速度可以提高11倍。
微软试图将WPF压缩到Arm的.net5框架中,但是他们无法及时完成,所以我们创建了一个在WoA上以本机模式运行的UWP应用程序。
在.NET6中,将包含Arm的WPF,因此让我们看看如何使用它。
注意:我们将使用最新的beta版本,所以可能会在发布的版本中有一些变化。
测试应用程序
我们将使用一个测试应用程序来解决一个众所周知的问题:旅行推销员问题(TSP)。
该应用程序的主要目的是能够在Aarch64上执行模拟版本和本机.net6wpf之间的速度基准测试。所以我们需要一些CPU密集型的东西,最好是一些图形化的东西来测试.NET6中WPF的功能。
用蛮力法求解TSP需要计算所有点之间的所有可能路径(组合)。这仍然是可行的约12点,但随后它变得非常缓慢。
要计算N个点之间的所有可能路径,需要计算N!路径。例如,在20个点之间找到最佳路径需要20的阶乘次(2432902008176640000)计算。即使在一台速度很快的电脑上,我们也活不了多久,看不到结果。
我们显然需要另一个解决办法。有几种可能性,但我们将实现一个遗传算法(GA)来寻找这个问题的最佳局部解决方案。实际实现超出了本文的范围。大部分我是如何实现它的描述是在旅行推销员-遗传算法。您可以在gverest/TravelingSalesman找到应用程序的源代码:使用遗传算法查找最佳路径。(https://github.com/GVerelst/TravelingSalesman)
以下是应用程序的要点:
- “生成路径”按钮生成一个新的随机路径。默认情况下,路径将有20个点。
种群大小决定了遗传算法的种群长度。默认设置为5000,这意味着每次迭代
- 计算了5000条路径的距离。
- 这5000条路是按长度排列的。
- 采用交叉和变异算法生成5000条新路径。
- 最佳路径显示在画布上。
- 随机种子用于伪随机发生器。从相同的数字开始总是会产生相同的数字序列。这样我们可以更好的比较时间来完成算法。
此版本中没有任何错误处理。在其中一个字段中输入非数字的内容,或者在不首先生成路径的情况下开始计算,都会使程序崩溃。如果您想验证数字输入,请查看下面的堆栈溢出文章:C#WPF How to use only numeric value in a textbox-Stack Overflow。
以下是1000000次计算后的算法结果:
这并不能保证是最好的可能的路径,但它已经过大量优化,很可能是一个可接受的解决方案。
初始应用程序是为.NET5编译的,因此它不会在Arm设备上运行。
使应用程序在Aarch64设备上运行
幸运的是,微软现在正在.NET6中实现WPF。在撰写本文时,6.0.0-preview.3版本已经可用。
目前还不支持直接在Arm上的Windows上安装Visual Studio 2019,使用现有的X64开发人员计算机是一个更快的开发部署调试周期
可以在Arm上的Windows上运行visualstudio,但它将在x86仿真模式下运行。这太慢了,工作起来不舒服,所以我们使用x64windows机器。
在我的例子中,我使用的是Microsoft Azure中的B4ms虚拟机,它有4个CPU内核、16GB RAM、8个最大连接磁盘(远远超过我们的需要)和2880 IOPS磁盘吞吐量,以确保良好的性能:
要准备开发机器,请首先将VisualStudio更新到最新版本(版本16.11或更高)。最简单的方法是使用visualstudio安装程序。然后安装.NET 6 SDK。
如果您想在VisualStudio2019中使用预览功能,您需要明确地这样说。在“选项”对话框(“工具”>“选项”)中,在“搜索”字段中输入“预览”,然后在左侧树中选择“预览要素”。搜索“使用.NET核心SDK预览”并选中复选框。需要重新启动Visual Studio。
重新打开VisualStudio时,您将在目标框架的下拉列表中找到.NET6.0。
在WPF和GA项目中,或者在测试项目中,都可以选择将目标框架设置为.NET6.0。现在我们可以重新编译应用程序了。
结果
这是一个WPF应用程序,使用Model-View-ViewMode(MVVM)模式,带有一些图形(绘制路径)和后台工作线程。所以它不是最基本的WPF应用程序。然而,这个构建并没有给我们任何错误或警告。
它运行起来没有任何问题,找到结果路径的时间与.NET5版本的程序大致相同。对于框架的最终版本来说,这看起来很有希望!
Aarch64本机.NET
在构建和运行Aarch64本机版本的应用程序之前,我们首先需要在Arm设备上安装.net6 preview,您可以在这里下载。我们甚至不需要在设备安装后重新启动它。
请注意,如果已经安装了x86.NET核心或.NET 5 SDK,则64位Arm.NET SDK不会覆盖其他SDK的路径变量–至少在最近的.NET 6预览版中是这样。这可能会在.NET6发行周期的后期发生变化。要在安装.NET6预览版后进行检查,请在终端中运行dotnet--info。您将看到如下内容:
PS C:\> dotnet --info
.NET SDK (reflecting any global.json):
Version: 5.0.100
Commit: 5044b93829
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19042
OS Platform: Windows
RID: win10-x86
Base Path: C:\Program Files (x86)\dotnet\sdk\5.0.100\
检查RID字段。如果上面写的是win10-arm64,那就很好了,您可以跳到下面的编译Aarch64部分。如果没有,则需要更新系统路径以包含arm64本机.NET SDK。为此,请打开Windows设置应用程序,搜索“环境变量”:
通过双击变量来验证用户变量中的路径变量:
确保您有一个读取C:\Program Files\dotnet的条目,如果您看到一个读取C:\Program Files(x86)\dotnet的条目,请将其删除。现在,如果运行dotnet–info,您将看到:
PS C:\Users\gvere> dotnet --info
.NET SDK (reflecting any global.json):
Version: 6.0.100-preview.3.21167.6
Commit: fa9dcf862f
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19042
OS Platform: Windows
RID: win10-arm64
Base Path: C:\Program Files\dotnet\sdk\6.0.100-preview.3.21167.6\
Host (useful for support):
Version: 6.0.0-preview.3.21167.1
Commit: 0f64b267ac
这可能只是我的设备上的一个问题,但是如果你遇到同样的问题,你现在知道该找什么了!我不是唯一一个有这个问题的人,如果你想了解更多信息,请检查:Windows找不到最新安装的.NET SDK-堆栈溢出。
为Aarch64编译
下面是让一切正常运转的最后步骤。
在开发机器上打开TSP.WPF项目并添加<RuntimeIdentifiers>元素,如下所示:
TSP.WPF.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<UseWPF>true</UseWPF>
<Authors>Gaston Verelst</Authors>
<Company>Faq.be bvba</Company>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\TSP.GA\TSP.GA.csproj" />
</ItemGroup>
</Project>
接下来,我们需要创建一个发布配置文件:
1.右键单击TSP.WPF项目并选择“发布…”…
2.对于目标,选择文件夹并单击下一步。
3.对于特定目标,也选择文件夹并单击下一步。
4.选择要发布的二进制文件的位置。通常情况下,默认值很好。如果使用共享文件夹部署到设备,可以在此处选择该文件夹,以便跳过复制文件。
5.单击“完成”创建初始发布配置文件。
6.在“更多选项”下,单击“编辑”。按如下所示设置值,然后单击“保存”。
7.单击“发布”。
将此文件夹复制到设备并运行应用程序。现在它在Arm设备上以64位本机模式运行,在.NET6上使用WPF!
结论
找到我们以前使用的相同路径的时间现在是1分23秒,这与开发VM差不多。我们可以再次说,运行.NET6和Aarch64设备是相当高的性能。
在.NET6上为WPF构建项目还需要一些额外的步骤,但不需要更改代码。
除了路径问题之外,在64位Windows on Arm机器上安装.net6非常简单。如果同时运行win10-x86和win10-arm64.NET SDK,请确保检查此项。
本机运行WPF应用程序只需要对.csproj文件做一些更改,并在选择了正确的目标运行时发布它。一旦这样做,应用程序运行没有问题!
下一步
尽管.NET6仍处于预览阶段,但WPF支持已经运行良好。正如我们所看到的,采用现有的x86/x64 WPF应用程序并在基于Aarch64的Windows机器上本机运行它相对简单。
如果您的WPF应用程序通过PInvoke调用本机C/C++库,或者使用包装C/C++库的NuGet包,则需要小心。如果您这样做了,您将需要这些库的Aarch64版本以本机方式运行您的应用程序。
如果遇到问题,此线程是开始寻求帮助的好地方。
有关.NET6的更多信息,请查看.NET6预览版3 |.NET博客(microsoft.com)。
许可证
本文以及任何相关的源代码和文件都是在代码项目开放许可证(CPOL)下授权的
关于作者
Gaston Verelst是Faq.be的所有者,这是一家位于比利时(啤酒和巧克力之乡)的IT咨询公司。到目前为止,他在职业生涯中经历了各种各样的项目。从Clipper87版开始,他在职业生涯的前15年转向C,主要是C++。
他很快意识到教书育人是非常有益的。1995年,他成为比利时第一批MCT之一。他教授不同主题的课程:
•C、C++、MFC、ATL、VB6、java脚本
•SQL Server(他也是MSDBA)
•面向对象分析和开发
•他创建了OMT和UML课程,并培训了数百名OO学生
•C#(来自第一个测试版)
•Web开发(来自ASP、ASP.NET、ASP.NET MVC)
•Windows开发(WPF、Windows窗体、WCF、实体框架等)
•更多
当然,只有亲身体验才能做到这一点。加斯顿曾为比利时最大的银行、汽车、印刷、政府和非政府组织参与过许多大型项目。他最新也是最伟大的项目是关于扩展msazure中构建的物联网网关。
“一切都应该尽可能简单,但不能简单!”爱因斯坦
加斯顿在他的所有项目中都应用了这一点。以最好的方式使用框架,他设法使代码更短、更稳定、更优雅。很明显,他拒绝按代码支付!
这导致了在https://msdev.pro. 这个博客的文章也可以在https://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=4423636,快乐阅读!
当他不工作或学习,Gaston 可以找到榻榻米在他的道场。他是Antwerp 附近柔术俱乐部赞申的首席教练,在许多武术方面也拥有很高的段位。
进一步了解Gaston 的链接:https://www.linkedin.com/in/gverelst/.