尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

WPF UI 版本迁移完全指南:从 v2、v3 到 v4 的 Breaking Changes 与升级实战

WPF UI 版本迁移完全指南:从 v2、v3 到 v4 的 Breaking Changes 与升级实战 WPF UI 版本迁移完全指南从 v2、v3 到 v4 的 Breaking Changes 与升级实战【免费下载链接】wpfuiWPF UI provides the Fluent experience in your known and loved WPF framework. Intuitive design, themes, navigation and new immersive controls. All natively and effortlessly.项目地址: https://gitcode.com/GitHub_Trending/wp/wpfui导读本文以 docs/migration/index.md 及其下 v2/v3/v4 三份迁移指南为核心系统梳理 WPF UIWpf.Ui跨大版本升级时必须掌握的破坏性变更、命名空间调整、导航体系重构与依赖注入改造方案。读完本文你将能够理清WPF-UI→Wpf.Ui的命名空间演变路径理解 v2 中NavigationStore/NavigationFluent/NavigationCompact与 v3NavigationView的关系掌握 v4 引入的Wpf.Ui.Abstractions与Wpf.Ui.DependencyInjection包的正确用法并完成一次面向 DI 的导航服务迁移。官方定位迁移指南是快速参考而非完整分步教程因此本文在保留全部要点的基础上结合当前仓库源码逐条佐证帮助你对照源码自查迁移后的代码是否符合预期。一、迁移概览三个大版本的演进主线WPF UI 的三大版本变更可以浓缩为三条主线版本核心变化迁移关键词v2全局命名空间改为 .NET 兼容的Wpf.Ui导航控件第三次重写标题栏控件重写命名空间、NavigationBase、导航不兼容v3所有导航控件合并为NavigationView图标体系统一为IconElement新增 WPF UI Gallery 取代 Demo 应用对话框类接口不兼容导航合并、IconElement、Gallery、对话框v4抽象接口拆分为独立包Wpf.Ui.AbstractionsIPageService更名为INavigationViewPageProvider新增Wpf.Ui.DependencyInjection包支持 DI 建页抽象包、DI、INavigationService迁移文档位于仓库 docs/migration 目录其中 index.md 是导航入口v2-migration.md、v3-migration.md、v4-migration.md 分别对应各版本的迁移要点。二、v2 迁移命名空间与导航控件重写2.1 全局命名空间变更WPF-UI→Wpf.Ui从版本 2.0 开始命名空间由WPF-UI改为更符合 .NET 惯例的Wpf.Ui。需要特别注意的是NuGet 包名并未改变这样做的目的是保持品牌和一致性。实际迁移操作!-- 旧写法v1 -- xmlns:uiclr-namespace:WPF-UI;assemblyWPF-UI !-- 新写法v2 -- xmlns:uiclr-namespace:Wpf.Ui;assemblyWpf.Ui同时所有using WPF-UI...形式的 C# 指令都要替换为using Wpf.Ui...。从当前仓库结构看核心程序集即 src/Wpf.Ui 目录命名空间统一为Wpf.Ui其下按功能划分Appearance、Controls、Interop、Markup、Converters等子命名空间见 src/Wpf.Ui/Controls 中 40 个控件目录。2.2 导航体系全部继承NavigationBasev2 的导航控件经历了第三次重写与旧版本几乎完全不兼容。所有导航控件都继承自Wpf.Ui.Controls.Navigation.NavigationBase基类v2 时代共有三个导航控件变体NavigationStore带侧边菜单的存储式导航NavigationFluentFluent 风格导航NavigationCompact紧凑模式导航。三个控件共享几乎相同的 XAML 结构只是根元素不同。以NavigationStore为例v2 文档原例ui:NavigationStore Frame{Binding ElementNameRootFrame} PrecacheFalse SelectedPageIndex-1 TransitionDuration200 TransitionTypeFadeInWithSlide ui:NavigationStore.Items ui:NavigationItem CacheTrue ContentHome IconHome24 PageTagdashboard PageType{x:Type pages:Dashboard} / ui:NavigationSeparator / /ui:NavigationStore.Items ui:NavigationStore.Footer ui:NavigationItem ClickNavigationButtonTheme_OnClick ContentTheme IconDarkTheme24 / /ui:NavigationStore.Footer /ui:NavigationStoreNavigationFluent与NavigationCompact的写法完全一致仅需替换根标签ui:NavigationFluent Frame{Binding ElementNameRootFrame} PrecacheFalse SelectedPageIndex-1 TransitionDuration200 TransitionTypeFadeInWithSlide !-- Items / Footer 内容同上 -- ui:NavigationFluent.Items ui:NavigationItem CacheTrue ContentHome IconHome24 PageTagdashboard PageType{x:Type pages:Dashboard} / ui:NavigationSeparator / /ui:NavigationFluent.Items /ui:NavigationFluentui:NavigationCompact Frame{Binding ElementNameRootFrame} PrecacheFalse SelectedPageIndex-1 TransitionDuration200 TransitionTypeFadeInWithSlide !-- Items / Footer 内容同上 -- ui:NavigationCompact.Items ui:NavigationItem CacheTrue ContentHome IconHome24 PageTagdashboard PageType{x:Type pages:Dashboard} / ui:NavigationSeparator / /ui:NavigationCompact.Items /ui:NavigationCompact这些 XAML 属性的含义属性作用Frame绑定到承载页面内容的Frame控件导航发生时页面被装载到该 FramePrecache是否在启动时预缓存页面False表示懒加载SelectedPageIndex初始选中的页面索引-1表示默认不选中任何项TransitionDuration页面切换动画时长毫秒例如200TransitionType切换动画类型例如FadeInWithSlide淡入滑动CacheNavigationItem单个页面是否缓存实例PageTag页面唯一标识供代码按 tag 导航PageType页面类型通过{x:Type}标记扩展引用Icon菜单项图标v2 使用Home24、DarkTheme24这类 Symbol 命名2.3 标题栏TitleBar重写v2 中标题栏控件同样被重写几乎完全不兼容。这一点在迁移时需要重点排查所有自定义标题栏样式与代码。从当前仓库看标题栏相关实现集中在 src/Wpf.Ui/Controls/TitleBar 与 src/Wpf.Ui/Controls/FluentWindowv3/v4 版本中标题栏已深度整合进FluentWindow并通过TitleBar控件提供可自定义区域。三、v3 迁移导航合并与图标体系重构3.1 导航控件合并为NavigationViewv3 最重要的变化所有导航控件合并为单一NavigationView设计灵感来自 WinUI 的 NavigationView。也就是说v2 时代的NavigationStore/NavigationFluent/NavigationCompact在 v3 中全部统一为一个控件通过PaneDisplayMode等属性控制显示形态左侧常规、紧凑、顶部等不再需要根据形态选择不同控件。当前仓库中导航实现位于 src/Wpf.Ui/Controls/NavigationView包含 21 个.cs文件与 13 个.xaml文件是整个控件库中最复杂的模块之一。其中 NavigationView.Navigation.cs 负责导航核心逻辑INavigationView.cs 定义了导航控件与页面提供服务的交互契约。v3 中NavigationView的基础用法ui:NavigationView x:NameRootNavigation Frame{Binding ElementNameRootFrame} PaneDisplayModeLeft ui:NavigationView.MenuItems ui:NavigationViewItem ContentHome IconHome24 TargetPageType{x:Type pages:Dashboard} / /ui:NavigationView.MenuItems /ui:NavigationView3.2 图标体系统一为IconElementv3 起所有图标基于新的IconElement控件体系替换了TitleBar、NavigationView、Button等控件中原有的图标实现。这意味着旧的IconHome24字符串式图标在部分场景被IconElement派生元素取代推荐使用SymbolIconFluent System Icons、FontIcon或ImageIcon作为图标资源对应 XAML 标记扩展位于 src/Wpf.Ui/Markup包括 FontIconExtension.cs、ImageIconExtension.cs、SymbolIconExtension.cs图标枚举定义在 src/Wpf.Ui/Controls/SymbolRegular.cs、src/Wpf.Ui/Controls/SymbolFilled.cs以及 src/Wpf.Ui/Controls/IconElement 目录。!-- v3 推荐写法SymbolIcon 显式声明图标 -- ui:NavigationViewItem ContentHome ui:NavigationViewItem.Icon ui:SymbolIcon SymbolHome24 / /ui:NavigationViewItem.Icon /ui:NavigationViewItem3.3 控制画廊Control Gallery受WinUI Controls Gallery启发项目创建了全新的WPF UI Gallery应用用于测试和浏览全部控件取代了旧的 Demo 应用。当前仓库中该应用位于 src/Wpf.Ui.Gallery包含 76 个页面 XAMLsrc/Wpf.Ui.Gallery/Views/Pages、70 个页面 ViewModelsrc/Wpf.Ui.Gallery/ViewModels/Pages以及控件清单定义 src/Wpf.Ui.Gallery/ControlsLookup/ControlPages.cs。它也是验证迁移结果的最佳工具迁移后可以对照 Gallery 中每个控件的用法确认 API 是否使用正确。3.4 对话框类接口不兼容ContentDialog、MessageBox、Snackbar在 v3 中被修改接口并非完全兼容。迁移时需要注意旧版对这三个控件的调用代码需要按新 API 重写建议对照 WPF UI Gallery 中的对应示例页面确认新用法如 src/Wpf.Ui.Gallery/Views/Pages 下的 ContentDialog、MessageBox、Snackbar 页面服务化调用可通过 src/Wpf.Ui/Extensions/ContentDialogServiceExtensions.cs 与 src/Wpf.Ui/Extensions/SnackbarServiceExtensions.cs 了解推荐的统一入口。四、v4 迁移抽象包拆分与 DI 化导航核心章节v4 是面向架构的一次大调整核心是把导航相关抽象从主程序集中剥离并让页面创建走依赖注入容器。这也是当前仓库中三个程序集分工的直接体现程序集仓库目录职责src/Wpf.Ui主包包含全部控件、服务与INavigationService实现src/Wpf.Ui.Abstractions抽象包包含导航接口、页面提供者契约、NavigationExceptionsrc/Wpf.Ui.DependencyInjectionDI 扩展包提供AddNavigationViewPageProvider()与默认页面提供者实现4.1 抽象包Wpf.Ui.Abstractions自动随主包引入v4 中部分 WPF UI 接口被移动到独立包WPF-UI.Abstractions程序集名Wpf.Ui.Abstractions。迁移时无需手动引用它——它总会随WPF-UINuGet 包自动引入。这一设计的意义在于如果你的模型Models、视图Views或其他业务服务位于一个与 WPF 无关的独立项目中现在可以脱离 WPF 程序集引用与多个应用程序共享开发这些导航契约从而实现更干净的跨项目复用。4.2 导航接口迁移到新命名空间INavigationAware与INavigableView已移动到Wpf.Ui.Abstractions.Controls命名空间。当前仓库源码证实src/Wpf.Ui.Abstractions/Controls/INavigationAware.cs 定义了两个异步钩子OnNavigatedToAsync()导航到该组件后触发与OnNavigatedFromAsync()导航离开前触发用于在页面/ViewModel 层面响应导航生命周期src/Wpf.Ui.Abstractions/Controls/INavigableView.cs 定义INavigableViewout T通过T ViewModel { get; }属性将 ViewModel 从 DataContext 中分离出来供INavigationView直接导航。迁移时的 using 变更// 旧命名空间 using Wpf.Ui.Controls; // v4 新命名空间 using Wpf.Ui.Abstractions.Controls;4.3IPageService→INavigationViewPageProvider重命名v4 中IPageService更名为INavigationViewPageProvider其默认实现转移到新的Wpf.Ui.DependencyInjection包。契约定义见 src/Wpf.Ui.Abstractions/INavigationViewPageProvider.cspublic interface INavigationViewPageProvider { /// 根据页面类型返回页面实例未找到时返回 null public object? GetPage(Type pageType); }配套的扩展方法位于 src/Wpf.Ui.Abstractions/NavigationViewPageProviderExtensions.cs提供强类型调用GetPageTPage()按类型取页面未找到返回nullGetRequiredPageTPage()按类型取页面未找到时抛出 src/Wpf.Ui.Abstractions/NavigationException.cs 定义的NavigationException。4.4 基于依赖注入的页面创建迁移后NavigationView将使用 DI 容器创建页面。只需要两步第一步注册服务Program.csvar builder Host.CreateDefaultBuilder(); builder.Services.AddNavigationViewPageProvider();AddNavigationViewPageProvider()的底层实现见 src/Wpf.Ui.DependencyInjection/ServiceCollectionExtensions.cs实际是把INavigationViewPageProvider注册为单例指向DependencyInjectionNavigationViewPageProviderpublic static IServiceCollection AddNavigationViewPageProvider(this IServiceCollection services) { _ services.AddSingleton INavigationViewPageProvider, DependencyInjectionNavigationViewPageProvider (); return services; }第二步把页面提供者挂到 NavigationView 上MyWindow.xaml.csvar pageProvider serviceProvider.GetRequiredServiceINavigationViewPageProvider(); // NavigationControl 是 XAML 中 NavigationView 的 x:Name NavigationControl.SetPageProviderService(pageProvider);SetPageProviderService的实现位于 src/Wpf.Ui/Controls/NavigationView/NavigationView.Navigation.cs本质是把提供者保存为内部页面服务字段public void SetPageProviderService(INavigationViewPageProvider navigationViewPageProvider) _pageService navigationViewPageProvider;默认提供者 src/Wpf.Ui.DependencyInjection/DependencyInjectionNavigationViewPageProvider.cs 的实现非常直观——直接委托给IServiceProviderpublic class DependencyInjectionNavigationViewPageProvider(IServiceProvider serviceProvider) : INavigationViewPageProvider { public object? GetPage(Type pageType) serviceProvider.GetService(pageType); }这意味着只要页面类型已注册到 DI 容器例如builder.Services.AddSingletonDashboardPage()NavigationView就能通过容器解析出页面实例页面的依赖如 ViewModel、服务也会随之自动注入。4.5 导航服务INavigationService强烈建议注册为 SingletonINavigationService定义在主包WPF-UI中用于简化导航管理方便在多个 ViewModel 之间注入使用。文档强烈建议将其注册为Singletonvar builder Host.CreateDefaultBuilder(); builder.Services.AddNavigationViewPageProvider(); builder.Services.AddSingletonINavigationService, NavigationService();为什么必须是 Singleton查看 src/Wpf.Ui/NavigationService.cs 的实现即可理解NavigationService通过构造函数接收INavigationViewPageProvider主构造参数pageProvider并维护一个NavigationControl字段——它需要在应用整个生命周期内保存唯一的NavigationView引用供所有 ViewModel 共享调用。如果注册为 Transient/Scoped每次解析都会得到新实例之前SetNavigationControl绑定的导航控件就会丢失。NavigationService提供的核心方法接口定义见 src/Wpf.Ui/INavigationService.cs方法说明Navigate(Type pageType)/Navigate(Type, object? dataContext)按页面类型导航可携带 DataContextNavigate(string pageTag)/Navigate(string, object? dataContext)按页面 tag/id 导航NavigateWithHierarchy(Type)同步将元素压入导航栈并导航适合面包屑层级场景GoBack()回到导航历史的上一条记录GetNavigationControl()获取当前绑定的INavigationView控件SetNavigationControl(INavigationView)绑定导航控件同时把页面提供者注入给该控件关键绑定逻辑在 src/Wpf.Ui/NavigationService.cspublic void SetNavigationControl(INavigationView navigation) { NavigationControl navigation; NavigationControl.SetPageProviderService(pageProvider); // 同步注入页面提供者 }因此在窗口初始化时你需要调用一次// MainWindow.xaml.cs navigationService.SetNavigationControl(RootNavigation);之后在任何 ViewModel 中注入INavigationService即可导航public class DashboardViewModel { private readonly INavigationService _navigationService; public DashboardViewModel(INavigationService navigationService) _navigationService navigationService; public void OpenSettings() _navigationService.Navigate(typeof(SettingsPage)); }五、迁移检查清单综合三个版本整理一份可执行的升级自检清单命名空间WPF-UI→Wpf.UiXAML 的xmlns与 C# 的using全部替换。导航控件v2 的NavigationStore/NavigationFluent/NavigationCompact→ v3 统一NavigationView确认Frame绑定、TransitionDuration、TransitionType等属性在新控件中是否可用。图标字符串式图标迁移为IconElement体系SymbolIcon/FontIcon/ImageIcon。对话框ContentDialog、MessageBox、Snackbar调用按新 API 重写可对照 src/Wpf.Ui.Gallery 示例页。抽象包INavigationAware/INavigableView改为Wpf.Ui.Abstractions.Controls命名空间无需手动引用Wpf.Ui.Abstractions包。页面提供者IPageService改名为INavigationViewPageProvider调用services.AddNavigationViewPageProvider()注册并通过SetPageProviderService()挂到NavigationView。导航服务AddSingletonINavigationService, NavigationService()注册窗口初始化时SetNavigationControl随后在 ViewModel 中注入使用。验证手段用 src/Wpf.Ui.GalleryWPF UI Gallery逐一对照控件用法也可参考 samples 下的Wpf.Ui.Demo.Mvvm与Wpf.Ui.Demo.Simple两个示例项目验证迁移后的完整工程结构。六、参考资源迁移指南入口docs/migration/index.mdv2 迁移docs/migration/v2-migration.mdv3 迁移docs/migration/v3-migration.mdv4 迁移docs/migration/v4-migration.md导航服务实现src/Wpf.Ui/NavigationService.cs、src/Wpf.Ui/INavigationService.cs抽象契约src/Wpf.Ui.Abstractions/INavigationViewPageProvider.cs、src/Wpf.Ui.Abstractions/Controls/INavigableView.cs、src/Wpf.Ui.Abstractions/Controls/INavigationAware.csDI 扩展src/Wpf.Ui.DependencyInjection/ServiceCollectionExtensions.cs、src/Wpf.Ui.DependencyInjection/DependencyInjectionNavigationViewPageProvider.cs导航控件实现src/Wpf.Ui/Controls/NavigationView控件画廊src/Wpf.Ui.GalleryMVVM 示例samples/Wpf.Ui.Demo.Mvvm【免费下载链接】wpfuiWPF UI provides the Fluent experience in your known and loved WPF framework. Intuitive design, themes, navigation and new immersive controls. All natively and effortlessly.项目地址: https://gitcode.com/GitHub_Trending/wp/wpfui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表