本文介绍如何将 Windows Presentation Foundation(WPF) 桌面应用升级到 .NET 8。 尽管 WPF 运行在 .NET 这个跨平台技术上,WPF 仍然是一个仅限于 Windows 的框架。 可以使用 .NET 升级助手升级以下 WPF 相关的项目类型:
- WPF 项目
- 控件库
- .NET 库
如果要从 .NET Framework 升级到 .NET,请考虑查看 WPF .NET 文章的差异 以及 从 .NET Framework 移植到 .NET 指南。
先决条件
- Windows 操作系统
- Visual Studio 2022 版本 17.7 或更高版本面向 .NET 8
- Visual Studio 2022 版本 17.1 或更高版本以目标 .NET 7
- 适用于 Visual Studio 的 .NET 升级助手扩展
演示应用
本文是在升级 Web 收藏夹示例 项目的上下文中编写的,可以从 .NET 示例 GitHub 存储库下载该项目。
启动升级
如果要升级多个项目,请从没有依赖项的项目开始。 在 Web 收藏夹示例中, WebSiteRatings 项目依赖于 StarVoteControl 库,因此应首先升级 StarVoteControl 。
小窍门
请务必对代码进行备份,例如在源代码管理中或副本中。
使用以下步骤在 Visual Studio 中升级项目:
- 右键单击解决方案资源管理器窗口中的 StarVoteControl 项目,然后选择“升级:   - 将打开一个新选项卡,提示你选择要执行升级的方式。 
- 选择“就地项目升级”。 
- 接下来,选择目标框架。 根据要升级的项目类型,将显示不同的选项。 如果库不依赖于 WPF 等桌面技术,并且可由 .NET Framework 项目和 .NET 项目使用,则 .NET Standard 2.0 是一个不错的选择。 但是,最新的 .NET 版本在语言和编译器方面进行了许多改进,比 .NET Standard 更为先进。 - 选择 .NET 8.0 ,然后选择“ 下一步”。 
- 此时将显示一个树状结构,其中包含与项目相关的所有工件,例如代码文件和库。 可以升级单个构件或整个项目(默认)。 选择“升级选择”以开始升级。 - 升级完成后,将显示结果:   - 具有实心绿色圆圈的工件已升级,而具有空心绿色圆圈的则被跳过。 跳过的生成工件意味着升级助手没有找到任何可以升级的内容。 
现在应用程序的支持库已升级,请升级主应用程序。
升级应用
升级所有支持库后,即可升级主应用项目。 执行以下步骤:
- 右键单击解决方案资源管理器窗口中的 WebSiteRatings 项目,然后选择“升级:
- 选择 就地项目升级 作为升级模式。
- 选择目标框架的 .NET 8.0 ,然后选择“ 下一步”。
- 保留选中所有项目,然后选择“升级选择”。
升级完成后,将显示结果。 如果物品带有警告图标,这表示有提示信息需要你阅读,你可以通过展开该物品来查看。
生成干净的内部版本
升级项目后,清理并编译它。
- 右键单击解决方案资源管理器窗口中的 WebSiteRatings 项目,然后选择“清理”。
- 右键单击解决方案资源管理器窗口中的 WebSiteRatings 项目,然后选择“生成”。
如果应用程序遇到任何错误,可以在“错误列表”窗口中找到这些错误,并提供修复这些错误的建议。
升级后的步骤
如果您的项目正在从 .NET Framework 升级到 .NET,请查阅 从 .NET Framework 升级到 .NET 后现代化 文章中的信息。
升级后,需要:
- 检查你的 NuGet 包。 - .NET 升级助手将某些包升级到了新版本。 使用本文中提供的示例应用, - Microsoft.Data.SqliteNuGet 包已从 1.0.0 升级到 8.0.x。 但是, 1.0.0 依赖于- SQLiteNuGet 包,但 8.0.x 会删除该依赖项。- SQLite项目仍引用 NuGet 包,但不再需要它。 可以从项目中删除- SQLite和- SQLite.Native这两个 NuGet 包。
- 清理旧的 NuGet 软件包。 - 不再需要packages.config 文件,并且可以从项目中删除,因为 NuGet 包引用现在在项目文件中声明。 此外,名为 Packages 的本地 NuGet 包缓存文件夹位于项目的文件夹或父文件夹中。 可以删除此本地缓存文件夹。 新的 NuGet 包引用使用用户配置文件目录中的全局缓存文件夹,文件夹位于 .nuget\packages,用于存储 NuGet 包。 
- 删除 - System.Configuration库。- 大多数 .NET Framework 应用引用库 - System.Configuration。 升级后,可能仍直接引用此库。- 该 - System.Configuration库使用 app.config 文件向应用提供运行时配置选项。 对于 .NET,此库已替换为- System.Configuration.ConfigurationManagerNuGet 包。 删除对库的引用,并将 NuGet 包添加到项目。
- 检查应用的现代化位置。 - 自 .NET 发布以来,API 和库发生了很大的变化。 在大多数情况下,.NET Framework 无法访问这些改进。 通过升级到 .NET,现在可以访问更现代的库。 - 下一个部分介绍您可以对本文使用的示例应用进行现代化的一些方面。 
现代化:网络浏览器控件
WebBrowser WPF 示例应用所引用的这个控件是基于 IE,IE 已过时。 WPF for .NET 可以使用基于 Microsoft Edge 的 WebView2 控件。 完成以下步骤以升级到新的 WebView2 Web 浏览器控件:
- 添加 - Microsoft.Web.WebView2NuGet 包。
- 在 MainWindow.xaml 文件中: - 将控件导入根元素中的 wpfControls 命名空间: - <mah:MetroWindow x:Class="WebSiteRatings.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:local="clr-namespace:WebSiteRatings" xmlns:vm="clr-namespace:WebSiteRatings.ViewModels" xmlns:VoteControl="clr-namespace:StarVoteControl;assembly=StarVoteControl" xmlns:wpfControls="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf" Loaded="MetroWindow_Loaded" mc:Ignorable="d" Title="My Sites" Height="650" Width="1000">
- 在 - <Border>元素声明的地方,删除- WebBrowser控件并用- wpfControls:WebView2控件替换它。- <Border Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="Black" Margin="5"> <wpfControls:WebView2 x:Name="browser" ScrollViewer.CanContentScroll="True" /> </Border>
 
- 编辑 MainWindow.xaml.cs 后台代码文件。 更新 - ListBox_SelectionChanged方法,将- browser.Source属性设置为有效的Uri。 此代码以前作为字符串传入网站 URL,但 WebView2 控件需要一个- Uri。- private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { var siteCollection = (ViewModels.SiteCollection)DataContext; if (siteCollection.SelectedSite != null) browser.Source = new Uri(siteCollection.SelectedSite.Url); else browser.NavigateToString("<body></body>"); }
根据应用用户运行的 Windows 版本,他们可能需要安装 WebView2 运行时。 有关详细信息,请参阅 WPF 应用中的 WebView2 入门。
现代化:appsettings.json
.NET Framework 使用 App.config 文件加载您的应用程序的设置,例如连接字符串和日志提供者。 .NET 现在使用 appsettings.json 文件进行应用设置。 在 .NET 中,通过  NuGet 包支持 System.Configuration.ConfigurationManager 文件,对appsettings.json 的支持由Microsoft.Extensions.Configuration NuGet 包提供。
随着其他库升级到 .NET,它们通过支持 appsettings.json 而不是 App.config实现现代化。例如,已为 .NET 6+ 升级的 .NET Framework 中的日志记录提供程序不再对设置使用 App.config 。 最好遵循他们的建议,并尽量避免使用 App.config 。
将 appsettings.json 与 WPF 示例应用配合使用
例如,升级 WPF 示例应用后,对本地数据库的连接字符串使用 appsettings.json 。
- System.Configuration.ConfigurationManager删除 NuGet 包。
- 添加 - Microsoft.Extensions.Configuration.JsonNuGet 包。
- 将文件添加到名为 appsettings.json的项目。 
- 将 appsettings.json 文件设置为复制到输出目录。 - 在解决方案资源管理器中选择文件后,使用“属性”窗口通过 Visual Studio 将副本设置为输出设置。 或者,可以直接编辑项目并添加以下内容 - ItemGroup:- <ItemGroup> <Content Include="appsettings.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> </ItemGroup>
- 将 App.config 文件中的设置迁移到新的 appsettings.json 文件。 - 在 WPF 示例应用中, app.config 仅包含单个连接字符串。 编辑 appsettings.json 文件以定义连接字符串: - { "ConnectionStrings": { "database": "DataSource=sqlite.db;" } }
- 编辑 App.xaml.cs 文件,实例化一个配置对象来加载 appsettings.json 文件,新增的行已被突出显示。 - using System.Windows; using Microsoft.Extensions.Configuration; namespace WebSiteRatings { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { public static IConfiguration Config { get; private set; } public App() { Config = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .Build(); } } }
- 在 .\Models\Database.cs 文件中,更改 - OpenConnection方法以使用新- App.Config属性。 这需要导入- Microsoft.Extensions.Configuration命名空间:- using Microsoft.Data.Sqlite; using System.Collections.Generic; using Microsoft.Extensions.Configuration; namespace WebSiteRatings.Models { internal class Database { public static SqliteConnection OpenConnection() => new SqliteConnection(App.Config.GetConnectionString("database")); public static IEnumerable<Site> ReadSites()- GetConnectionString是命名空间提供的- Microsoft.Extensions.Configuration扩展方法。