mcpField
D
dotnet-wpf-migration

dotnet-wpf-migration

github.com/wshaddix开发8686 次安装35 周前更新
代码仓库

关于 dotnet-wpf-migration

dotnet-wpf-migration 是帮助团队现代化 Windows 桌面应用的迁移指导技能,涵盖升级到现代 .NET,以及在 WPF、WinUI 3 和 Uno Platform 之间迁移,并依据项目约束梳理路径。

主要功能

  1. 01WPF .NET Framework 升级到 .NET 8+
  2. 02WinForms .NET Framework 升级到 .NET 8+
  3. 03从 WPF 迁移到 WinUI 3
  4. 04从 WPF 迁移到 Uno Platform
  5. 05UWP 迁移路径
  6. 06比较迁移工作量与风险

适用场景

  1. 01保留界面并升级 WPF 应用
  2. 02现代化 WinForms 应用运行时
  3. 03将 WPF 视图改写为 WinUI 3
  4. 04推动 WPF 代码库支持跨平台目标

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-wpf-migration

安装后在 Claude Code 中输入/dotnet-wpf-migration确认已加载。

详细介绍

dotnet-wpf-migration

面向 Windows 桌面应用程序的上下文相关迁移指南。涵盖 WPF .NET Framework 迁移到 .NET 8+、WPF 迁移到 WinUI 3(仅限 Windows 的现代化)、WPF 迁移到 Uno Platform(跨平台)、WinForms .NET Framework 迁移到 .NET 8+、UWP 迁移到 WinUI 3、UWP 迁移到 Uno Platform(交叉引用),以及根据项目约束选择合适迁移目标的决策矩阵。

**版本假设:**以 .NET 8.0+ 为基准(当前 LTS)。自动迁移使用 dotnet-upgrade-assistant。适用时会明确标注 .NET 9 功能。

**范围边界:**此技能负责桌面框架之间的迁移路径,以及从 .NET Framework 迁移到现代 .NET 的路径。各框架的模式(现代 WPF、WinUI、现代 WinForms)由相应的框架技能负责。框架选择决策树由 [skill:dotnet-ui-chooser] 负责。

**范围之外:**WPF .NET 8+ 开发模式——参见 [skill:dotnet-wpf-modern]。WinUI 3 开发模式——参见 [skill:dotnet-winui]。WinForms .NET 8+ 开发模式——参见 [skill:dotnet-winforms-basics]。Uno Platform 开发模式——参见 [skill:dotnet-uno-platform]。框架选择决策树——参见 [skill:dotnet-ui-chooser]。桌面测试——参见 [skill:dotnet-ui-testing-core]。

交叉引用:[skill:dotnet-wpf-modern](WPF .NET 8+ 模式)、[skill:dotnet-winui](WinUI 3 模式)、[skill:dotnet-winforms-basics](WinForms .NET 8+ 模式)、[skill:dotnet-uno-platform](Uno Platform 模式)、[skill:dotnet-ui-chooser](框架选择)、[skill:dotnet-ui-testing-core](桌面测试)。


迁移路径概览

根据当前框架和目标选择迁移路径。每条路径在工作量、风险和能力提升方面各有不同权衡。

当前框架目标框架工作量风险适用情况
WPF .NET FrameworkWPF .NET 8+低到中低现代化运行时,保留现有 UI
WPF .NET FrameworkWinUI 3高中采用现代 Windows UI、触控/笔输入和 Fluent
WPF .NET FrameworkUno Platform高中到高需要跨平台
WinForms .NET FrameworkWinForms .NET 8+低低现代化运行时,保留现有 UI
UWPWinUI 3中中保持仅限 Windows,同时使用现代运行时
UWPUno Platform中到高中需要从 UWP 实现跨平台

WPF .NET Framework 迁移到 .NET 8+

风险最低的迁移路径。保留现有 XAML 和代码隐藏,同时迁移到现代 .NET,以获得更好的性能、DI 支持和并行部署能力。

使用 dotnet-upgrade-assistant

.NET Upgrade Assistant 可自动完成大部分迁移工作:

# Install the upgrade assistant
dotnet tool install -g upgrade-assistant

# Analyze the project first (non-destructive)
upgrade-assistant analyze MyWpfApp.sln

# Upgrade the project
upgrade-assistant upgrade MyWpfApp.sln

Upgrade Assistant 可处理的内容:

  • 将 .csproj 从旧格式转换为 SDK 样式
  • 将 packages.config 迁移为 PackageReference
  • 将 TFM 更改为 net8.0-windows
  • 将 AssemblyInfo.cs 属性移至 .csproj
  • 替换常见 API 并更新命名空间

需要手动处理的内容:

  • 将 App.config 设置迁移到 appsettings.json 或 Host 构建器配置
  • 迁移 Settings.settings / My.Settings(VB.NET)
  • 更新第三方控件库(确认供应商提供的版本兼容 .NET 8)
  • 处理 WCF 客户端引用(使用 CoreWCF,或迁移到 gRPC/REST)
  • 调整 COM 互操作(System.Runtime.InteropServices 中的语法差异)
  • 自定义 MSBuild 目标和构建脚本
API 兼容性

.NET Framework 和 .NET 8+ 中的大多数 WPF API 都相同。主要差异如下:

领域.NET Framework.NET 8+操作
剪贴板Clipboard.SetText()API 相同无需更改
打印PrintDialog、PrintVisualAPI 相同无需更改
BitmapEffect已弃用(由软件渲染)已移除使用 Effect / ShaderEffect
DrawingContext.PushEffect可用已移除使用 ShaderEffect
XPS 文档System.Windows.Xps需要 NuGet 包添加 System.Windows.Xps PackageReference
语音合成System.Speech需要 NuGet 包添加 System.Speech PackageReference
NuGet 包更新

迁移后,将 NuGet 包更新为兼容 .NET 8 的版本:

# List outdated packages
dotnet list package --outdated

# Update packages (one at a time for safer migration)
dotnet add package Newtonsoft.Json --version 13.*
dotnet add package MaterialDesignThemes --version 5.*

常见的包替换:

  • Unity 容器 -> Microsoft.Extensions.DependencyInjection(内置)
  • Autofac -> 更新到最新版本(支持 .NET 8)
  • log4net / NLog -> 可考虑使用 Microsoft.Extensions.Logging 搭配 Serilog 或 NLog 提供程序
  • EntityFramework(EF6)-> Microsoft.EntityFrameworkCore 8.x
重大变更检查清单
  • 默认高 DPI 行为已更改。 .NET 8 WPF 默认启用 PerMonitorV2 DPI 感知(而非 .NET Framework 中的 SystemAware)。
  • 可空引用类型。 新项目会启用 NRT。现有代码可能会产生警告。可先通过 <Nullable>disable</Nullable> 禁用,然后逐步修复。
  • 隐式 using。 新的 SDK 风格项目会启用隐式 using,可能与现有的 using 语句冲突。如有需要,可通过 <ImplicitUsings>disable</ImplicitUsings> 禁用。
  • 程序集加载。 AssemblyLoadContext 取代 AppDomain,用于隔离程序集。使用 AppDomain.CreateDomain 的插件架构需要重新设计。
  • 运行时行为。 .NET 8 的 GC 在 Gen0/Gen1 回收时更加积极。依赖终结器的代码行为可能会有所不同。

有关迁移后的 WPF 模式(Host 构建器、MVVM Toolkit、现代 C#),请参阅 [skill:dotnet-wpf-modern]。


从 WPF 迁移到 WinUI 3

如果需要现代 Windows 原生 UI(Fluent Design、触控/笔输入、Windows 11 集成〔小组件、Mica〕)或在现代 .NET 上使用 UWP 风格的 API,可进行迁移。这需要部分重写——XAML 概念可以沿用,但 API 和命名空间有所不同。

适合采用此迁移路径的情况
  • 应用是仅限 Windows的,并且将继续仅支持 Windows
  • 需要现代 Fluent Design 控件、触控/笔支持或 Windows 11 功能
  • 团队愿意投入 XAML 重写工作
  • 应用正在积极开发,并持续添加功能(足以证明这项投入是值得的)
可考虑其他方案的情况
  • 如果需要跨平台 -> 改用 Uno Platform(WinUI XAML 表面)
  • 如果应用处于维护模式 -> 改用 WPF .NET 8+(工作量较小)
  • 如果 WPF Fluent 主题(.NET 9+)已满足需求 -> 继续使用 WPF .NET 8+,并设置 ThemeMode = ThemeMode.System
XAML 差异
WPF XAMLWinUI 3 XAML说明
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"相同的 URI(但解析为 Microsoft.UI.Xaml 类型,而不是 System.Windows)无需更改 xmlns,但运行时类型不同
{Binding Path=Name}{x:Bind Name, Mode=OneWay}优先使用 x:Bind(已编译,类型安全)
DataContext 绑定代码隐藏属性 + x:Bindx:Bind 根据代码隐藏解析
Window 继承自 System.Windows.WindowWindow 继承自 Microsoft.UI.Xaml.Window基类和 API 不同
UserControlUserControl(Microsoft.UI.Xaml 命名空间)概念相同,命名空间不同
带有 TargetType 的 Style相同用法相同
DataTemplate使用 x:Bind 时需要 x:DataType编译绑定所必需
ContextMenuMenuFlyout控件类型不同
StatusBar无内置等效项使用自定义 CommandBar 或 InfoBar
RibbonControl无内置等效项使用 NavigationView + CommandBar
迁移策略
  1. 在现有 WPF 项目旁创建一个新的 WinUI 3 项目
  2. 首先迁移共享逻辑 ——模型、服务、ViewModel(如果使用 MVVM Toolkit,这些内容可在两者中通用)
  3. 逐步迁移视图 ——从较简单的页面开始,再迁移复杂页面
  4. 将 WPF 专用控件替换为 WinUI 对应控件(见上表)
  5. 将数据绑定从 {Binding} 更新为 {x:Bind},以确保编译时安全
  6. 测试 Windows 集成功能(通知、生命周期、文件关联)
  7. 选择部署模型 ——MSIX(应用标识)或未打包(xcopy)

如需了解 WinUI 3 模式和项目设置,请参阅 [skill:dotnet-winui]。


WPF 到 Uno Platform

当你需要让 WPF 代码库跨平台运行时,可进行迁移。Uno Platform 使用 WinUI XAML API,因此 WPF XAML 技能可以部分迁移,但迁移过程中仍需适配 WinUI XAML 模式。

适用场景
  • 应用需要在多个平台上运行(Windows、macOS、Linux、Web、移动设备)
  • 团队具备可迁移到 WinUI XAML 的 WPF/XAML 专业知识
  • 愿意投入资源进行跨平台适配(平台专属行为、响应式布局)
考虑其他方案的场景
  • 如果仅面向 Windows -> 迁移到 WinUI 3(更简单,无跨平台开销)
  • 如果应用处于维护模式 -> 迁移到 WPF .NET 8+(所需工作量最少)
  • 如果团队具备 Web 技能 -> 考虑使用 Blazor 交付 Web 应用
迁移方法

从 WPF 迁移到 Uno Platform 的方法与迁移到 WinUI 3 类似(因为 Uno 使用 WinUI API),但还需考虑额外的跨平台因素:

  1. 创建 Uno Platform 项目并指定所需的目标平台
  2. 迁移 ViewModel 和服务——这些内容与平台无关
  3. 将 XAML调整为 WinUI 语法(与从 WPF 迁移到 WinUI 时的改动相同)
  4. 使用条件编译或 Uno 平台扩展处理平台专属功能
  5. 将仅适用于 Windows 的 API替换为跨平台替代方案(文件对话框、通知等)
  6. 测试每个目标平台——在 Skia 和原生目标平台上,渲染效果和行为可能有所不同
Uno Extensions 对常见模式的替代方案

Uno Extensions 为常见的 WPF 模式提供跨平台替代方案:

WPF 模式Uno Extensions 替代方案
自定义导航Uno.Extensions.Navigation
手动设置 DIUno.Extensions.DependencyInjection(封装 MS DI)
appsettings.json 配置Uno.Extensions.Configuration
手动创建 HTTP 客户端Uno.Extensions.Http(使用 Refit 的类型化客户端)
手动序列化Uno.Extensions.Serialization

如需了解 Uno Platform 开发模式,请参阅 [skill:dotnet-uno-platform]。如需了解各目标平台的部署指南,请参阅 [skill:dotnet-uno-targets]。


WinForms .NET Framework 到 .NET 8+

与 WPF 迁移类似,但由于 WinForms 的项目结构不那么复杂,通常更简单。

使用 dotnet-upgrade-assistant
# Analyze first
upgrade-assistant analyze MyWinFormsApp.sln

# Upgrade
upgrade-assistant upgrade MyWinFormsApp.sln

升级助手可处理的内容:

  • 将 .csproj 转换为 SDK 风格,并添加 <UseWindowsForms>true</UseWindowsForms>
  • 将 TFM 更改为 net8.0-windows
  • 将 packages.config 转换为 PackageReference
  • 将 AssemblyInfo.cs 迁移至项目属性

需要手动处理的内容:

  • 迁移 App.config / Settings.settings
  • 将 My.Settings(VB.NET)迁移至现代配置
  • 更新第三方控件库(部分 WinForms 控件可能不支持 .NET 8)
  • 处理 Crystal Reports 或其他旧版报表工具(评估替代方案)
  • 调整 COM 互操作
设计器兼容性

WinForms 设计器文件(.Designer.cs)通常可以顺利迁移。Visual Studio 中适用于 .NET 8+ 的 WinForms 设计器已全面支持。

已知设计器问题:

  • 可能需要更新自定义设计器序列化程序
  • 部分第三方控件可能无法在 .NET 8 设计器中呈现
  • .NET 9+ 提供不感知 DPI 的设计器模式(<ForceDesignerDPIUnaware>true</ForceDesignerDPIUnaware>)
迁移后的现代化改造

迁移到 .NET 8+ 后,可考虑逐步采用现代模式:

  • 通过 Host builder 添加依赖注入(参见 [skill:dotnet-winforms-basics])
  • 将同步调用替换为 async/await
  • 启用高 DPI,使用 PerMonitorV2 模式
  • 启用深色模式(.NET 9+ 中为实验性功能)

有关 WinForms .NET 8+ 模式,请参见 [skill:dotnet-winforms-basics]。


UWP 到 WinUI 3

WinUI 3 是 UWP 的自然迁移目标。WinUI 3 使用相同的 XAML API 接口,但命名空间有所变化。

命名空间变更

主要迁移工作是将命名空间从 Windows.UI.* 更新为 Microsoft.UI.*:

UWP 命名空间WinUI 3 命名空间
Windows.UI.XamlMicrosoft.UI.Xaml
Windows.UI.Xaml.ControlsMicrosoft.UI.Xaml.Controls
Windows.UI.Xaml.MediaMicrosoft.UI.Xaml.Media
Windows.UI.CompositionMicrosoft.UI.Composition
Windows.UI.TextMicrosoft.UI.Text

保持不变: Windows.Storage、Windows.Networking、Windows.Security、Windows.ApplicationModel、Windows.Devices —— 这些 WinRT API 保持不变。

应用模型差异
关注点UWPWinUI 3
应用生命周期CoreApplication + 挂起Windows App SDK AppInstance
窗口管理Window.Current(单例)手动跟踪窗口引用
调度程序CoreDispatcher.RunAsyncDispatcherQueue.TryEnqueue
后台任务内置,需要包标识使用 MSIX 时可用,不使用时受限
文件访问通过清单授予广泛的访问权限标准 Win32 文件访问 + StorageFile
Store APIWindows.Services.Store相同(仍然可用)
迁移步骤
  1. 使用 Windows App SDK 模板创建新的 WinUI 3 项目
  2. 复制源文件并更新命名空间(将 Windows.UI.Xaml 改为 Microsoft.UI.Xaml)
  3. 替换已弃用的 API(将 Window.Current 改为手动跟踪,将 CoreDispatcher 改为 DispatcherQueue)
  4. 将 MSIX 清单从 UWP 格式更新为 Windows App SDK 格式
  5. 迁移功能——检查并更新功能声明
  6. 更新 NuGet 包至兼容 Windows App SDK 的版本
  7. 测试 Windows 集成——通知、后台任务和文件关联的行为可能有所不同

UWP .NET 9 预览路径: Microsoft 宣布了对 .NET 9 上 UWP 的预览支持。如果全面迁移到 WinUI 3 的成本过高,这条路径可让 UWP 应用使用现代 .NET 运行时功能,而无需迁移 UI 框架。

有关 WinUI 3 开发模式,请参见 [skill:dotnet-winui]。


UWP 到 Uno Platform

当需要让 UWP 代码库支持跨平台时。Uno Platform 实现了 WinUI XAML API 表面,因此是 UWP 最自然的跨平台迁移路径。

由于 Uno Platform 使用的 WinUI XAML API 表面与 UWP XAML 基于的 API 表面相同,因此与迁移到其他跨平台框架相比,大部分 UWP 代码只需较少修改即可迁移:

  • XAML 文件通常只需少量修改即可使用(Uno 支持 x:Bind、x:Load 等)
  • ViewModel 和服务可直接迁移(与平台无关的代码)
  • Windows 专属 API需要为非 Windows 目标平台采用跨平台替代方案
关键注意事项
  • 使用 Windows.* API 的平台专属代码需要通过条件编译或抽象处理,以支持非 Windows 目标平台
  • WinRT API(传感器、地理定位、媒体捕获)需要使用 Uno 实现或平台专属替代方案
  • MSIX 打包仅适用于 Windows;其他平台使用各自的原生分发机制

有关 Uno Platform 开发模式,请参阅 [skill:dotnet-uno-platform]。有关各目标平台的部署,请参阅 [skill:dotnet-uno-targets]。


决策矩阵

使用此矩阵选择迁移路径。正确的选择取决于你的具体限制条件,不存在通用的“最佳”迁移目标。

按主要目标选择
目标推荐路径替代方案
风险最低、迁移最快WPF/WinForms 迁移到 .NET 8+--
现代 Windows UIWPF 迁移到 WinUI 3使用 Fluent 主题的 WPF .NET 9+
从 Windows 应用实现跨平台WPF 迁移到 Uno Platform在 Blazor 中重写关键路径
从 UWP 实现跨平台UWP 迁移到 Uno PlatformUWP 迁移到 WinUI 3(仅限 Windows)
UWP 现代化(仅限 Windows)UWP 迁移到 WinUI 3UWP on .NET 9 preview
旧版 WinForms 现代化WinForms 迁移到 .NET 8+在 Blazor 或 WPF 中逐步重写
按限制条件选择
限制条件最佳路径原因
预算/时间有限迁移到 .NET 8+(相同框架)工作量最低,代码库不变
必须仅支持 WindowsWinUI 3 或 WPF .NET 8+WinUI 适用于现代 UI;WPF 改动最少
必须支持跨平台Uno Platform借助 WinUI XAML API 表面实现最广泛的平台覆盖
已有大型 WPF 代码库先迁移到 WPF .NET 8+,然后再评估在重写 UI 前,先稳定运行于现代运行时
已有 UWP 代码库WinUI 3(Windows)或 Uno(跨平台)与现有代码最接近的 API 表面
团队具备 Web 技能Blazor(重写)将 Web 专业知识用于桌面/移动端
分阶段迁移策略

对于大型应用,分阶段迁移可以降低风险:

  1. 阶段 1:运行时迁移——从 .NET Framework 迁移到 .NET 8+(UI 框架不变)。验证兼容性、提升性能,并支持使用现代 NuGet 包。
  2. 阶段 2:模式现代化——采用 Host 构建器、DI、MVVM Toolkit 和现代 C#。请参阅 [skill:dotnet-wpf-modern] 或 [skill:dotnet-winforms-basics]。
  3. 阶段 3:UI 迁移(如有需要)——根据需求迁移到 WinUI 3、Uno Platform 或 Blazor。只有在阶段 1 和 2 稳定后才进行此步骤。

此方法可避免“大爆炸式”重写的风险,并在每个阶段逐步带来价值。


Agent 注意事项

  1. 在了解约束条件之前,不要将某个迁移目标推荐为“正确选择”。 始终列出各种选项及其权衡。预算、时间安排、团队专业能力和平台要求都会影响决策。
  2. 在建议更换 UI 框架之前,不要跳过 .NET 8+ 运行时迁移。 从 .NET Framework 迁移到 .NET 8+(使用相同的 UI 框架)应作为第 1 阶段。从 .NET Framework 将 WPF 迁移到 WinUI,要比从 .NET 8+ 迁移困难得多。
  3. 不要认为 WPF 已是“旧技术”而必须迁移离开。 .NET 8+ 上的 WPF 仍在积极维护,并持续推出新功能(.NET 9+ 中的 Fluent 主题、性能改进)。许多应用继续使用 WPF 就能很好地满足需求。
  4. 不要在未先运行 analyze 的情况下使用 dotnet-upgrade-assistant。 升级前务必先进行分析,以了解变更范围和潜在问题。
  5. 不要混淆 WPF XAML 与 WinUI XAML。 虽然概念相似,但 API 表面不同(Window、DataContext 与 x:Bind、NavigationView 模式)。迁移所需的不只是更改命名空间。
  6. 不要忘记,UWP 迁移到 WinUI 3 涉及应用模型变更,而不仅仅是更新命名空间。 Window.Current、CoreDispatcher、CoreApplication API 都被不同模式取代。
  7. 不要为仅面向 Windows 的简单应用推荐 Uno Platform。 如果应用不需要跨平台,WinUI 3 或 WPF .NET 8+ 更简单,维护开销也更低。

参考资料

评论

支持 Markdown