阅读目录
1、介绍
2、框架安装
2.1、手动引入框架
2.2、安装模板,创建项目
3、框架使用
3.1、属性绑定
3.2、事件绑定
3.3、区域注册使用
3.4、模块化使用
3.5、导航功能(传递参数)
3.6、导航功能(拦截页面切换)
3.7、导航功能(导航日志)
3.8、对话服务(弹窗模态框)
3.9、发布订阅(消息推送)
4、参考
Prism 是一个用于在 WPF、Xamarin Forms、Uno Platform 和 WinUI 中构建松散耦合、可维护和可测试的 XAML 应用程序框架,每个平台都有单独的版本。Prism 提供了一组设计模式的实现,这些设计模式有助于编写结构良好且可维护的 XAML 应用程序,包括 MVVM、依赖注入、命令、EventAggregator 等。
核心包
这些是每个平台的基础包,以及作为跨平台 PCL 的 Prism 核心组件。
平台 | 包 | NuGet | 赞助商连接 |
---|---|---|---|
跨平台 | Prism.Core | ||
WPF | Prism.Wpf | ||
Xamarin.Forms | Prism.Forms | ||
Uno 平台和 WinUI | Prism.Uno |
特定于容器的包
每个受支持的 IoC 容器都有自己的包,可帮助设置和使用该容器以及 Prism。该组件使用此约定命名:Prism.[Container].[Platform] .dll,例如Prism.Unity.Wpf.dll。从 7.0 版开始,Prism 正在为每个平台提供单独的包。请务必为您选择的容器和平台安装软件包。
WPF
包 | NuGet | 赞助商连接 |
---|---|---|
Prism.DryIoc | ||
Prism.Unity |
Xamarin Forms
包 | NuGet | 赞助商连接 |
---|---|---|
Prism.DryIoc.Forms | ||
Prism.Unity.Forms | ||
Prism.Forms.Regions |
Uno Platform
包 | NuGet | 赞助商连接 |
---|---|---|
Prism.DryIoc.Uno | ||
Prism.Unity.Uno |
①创建WPF项目,我这里使用的是NET6版本创建的;
②Nuget添加包Prism.DryIoc,删除MainWindow.xaml文件;
③App.xaml.cs里添加命名空间using Prism.DryIoc;
④修改public partial class App : Application 为 public partial class App : PrismApplication;
⑤修App.xaml的命名空间为PrismApplication;

1 <prism:PrismApplication x:Class="ITL.Mom.Scada.UAApp.App" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:local="clr-namespace:ITL.Mom.Scada.UAApp" 5 xmlns:prism="http://prismlibrary.com/"> 6 <Application.Resources> 7 </Application.Resources> 8 </prism:PrismApplication>
⑥App.xaml里删除XAML启动代码 StartupUri="MainWindow.xaml",新建Views和ViewModels文件夹,里面分别创建Windows窗口MainView.xaml和MainViewModel;

1 using Prism.Mvvm; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ITL.Mom.Scada.UAApp.ViewModels 9 { 10 public class MainViewModel:BindableBase 11 { 12 #region MVVM属性绑定-窗口标题 + public string Title 13 private string _title = "数据库自动维护"; 14 public string Title 15 { 16 get { return _title; } 17 set { _title = value; RaisePropertyChanged(); } 18 } 19 #endregion 20 } 21 }

1 <Window x:Class="ITL.Mom.Scada.UAApp.Views.MainView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:ITL.Mom.Scada.UAApp.Views" 7 xmlns:prism="http://prismlibrary.com/" 8 prism:ViewModelLocator.AutoWireViewModel="True" 9 mc:Ignorable="d" 10 Title="{Binding Title}" Height="225" Width="400"> 11 <Grid> 12 13 </Grid> 14 </Window>
⑦App.xaml.cs里实现抽象类;

1 using Prism.DryIoc; 2 using Prism.Ioc; 3 using System.Windows; 4 namespace ITL.Mom.Scada.UAApp 5 { 6 /// <summary> 7 /// Interaction logic for App.xaml 8 /// </summary> 9 public partial class App : PrismApplication 10 { 11 protected override Window CreateShell() 12 { 13 return Container.Resolve<MainWindow>(); 14 } 15 16 protected override void RegisterTypes(IContainerRegistry containerRegistry) 17 { 18 //依赖注入 19 } 20 } 21 }
⑧以上完成手动引入Prism框架;

1 <prism:PrismApplication x:Class="ITL.Mom.Scada.UAApp.App" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:local="clr-namespace:ITL.Mom.Scada.UAApp" 5 xmlns:prism="http://prismlibrary.com/"> 6 <Application.Resources> 7 8 </Application.Resources> 9 </prism:PrismApplication>

1 using Prism.DryIoc; 2 using Prism.Ioc; 3 using System; 4 using System.Collections.Generic; 5 using System.Configuration; 6 using System.Data; 7 using System.Linq; 8 using System.Threading.Tasks; 9 using System.Windows; 10 11 namespace ITL.Mom.Scada.UAApp 12 { 13 /// <summary> 14 /// Interaction logic for App.xaml 15 /// </summary> 16 public partial class App : PrismApplication 17 { 18 protected override Window CreateShell() 19 { 20 return Container.Resolve<MainWindow>(); 21 } 22 23 protected override void RegisterTypes(IContainerRegistry containerRegistry) 24 { 25 //依赖注入 26 } 27 } 28 }
①VS工具栏=》扩展(X)=》管理扩展,安装Prism模板
①项目下创建Views文件夹,存放交互的页面,项目下创建ViewModels文件夹,存放交互页面的ViewModel;
②Views下添加测试主页面MainView.xaml,ViewModels下面添加对应的ViewModel文件MainViewModle.cs;
③在MainView.xaml里添加Prism的引用,配置自动查找ViewModel;
④在MainViewModel.cs里添加绑定是属性;
⑤以上就完成了属性绑定,下面是完整代码;

1 <Window x:Class="Demo36_WPFPrism.Views.MainView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.Views" 7 xmlns:prism="http://prismlibrary.com/" 8 prism:ViewModelLocator.AutoWireViewModel="True" 9 mc:Ignorable="d" 10 Title="{Binding TitleText}" Height="450" Width="800"> 11 <Grid> 12 13 </Grid> 14 </Window>

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Prism.Commands; 7 using Prism.DryIoc; 8 using Prism.Mvvm; 9 10 namespace Demo36_WPFPrism.ViewModels 11 { 12 public class MainViewModel : BindableBase 13 { 14 #region 属性绑定-窗口标题 15 private string _titleText="测试主页面"; 16 17 public string TitleText 18 { 19 get { return _titleText; } 20 set { _titleText = value; RaisePropertyChanged(); } 21 } 22 #endregion 23 24 } 25 }
①在Views文件夹下分别添加三个用户控件:UserControlA.xaml、UserControlB.xaml、UserControlC.xaml;
②修改MainViewModel.cs文件,添加委托事件代码;
③修改MainView.xaml文件,添加三个按钮和一个内容控件;
④以上完成事件绑定,下面是完整代码;

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Demo36_WPFPrism.Views; 7 using Prism.Commands; 8 using Prism.DryIoc; 9 using Prism.Mvvm; 10 11 namespace Demo36_WPFPrism.ViewModels 12 { 13 public class MainViewModel : BindableBase 14 { 15 #region 属性绑定-窗口标题 16 private string _titleText="测试主页面"; 17 18 public string TitleText 19 { 20 get { return _titleText; } 21 set { _titleText = value; RaisePropertyChanged(); } 22 } 23 #endregion 24 25 private object _body; 26 27 public object Body 28 { 29 get { return _body; } 30 set { _body = value; RaisePropertyChanged(); } 31 } 32 33 public DelegateCommand<string> OpenCommand { get; set; } 34 public MainViewModel() 35 { 36 OpenCommand=new DelegateCommand<string>(Open); 37 } 38 private void Open(string obj) 39 { 40 switch (obj) 41 { 42 case "ViewA": Body = new UserControlA(); break; 43 case "ViewB": Body = new UserControlB(); break; 44 case "ViewC": Body = new UserControlC(); break; 45 default: 46 break; 47 } 48 } 49 } 50 }

1 <Window x:Class="Demo36_WPFPrism.Views.MainView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.Views" 7 xmlns:prism="http://prismlibrary.com/" 8 prism:ViewModelLocator.AutoWireViewModel="True" 9 mc:Ignorable="d" 10 Title="{Binding TitleText}" Height="450" Width="800"> 11 <Grid> 12 <Grid.RowDefinitions> 13 <RowDefinition Height="40"/> 14 <RowDefinition/> 15 </Grid.RowDefinitions> 16 <StackPanel Orientation="Horizontal"> 17 <Button Content="显示ViewA" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewA"/> 18 <Button Content="显示ViewB" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewB"/> 19 <Button Content="显示ViewC" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewC"/> 20 </StackPanel> 21 <ContentControl Grid.Row="1" Content="{Binding Body}"/> 22 </Grid> 23 </Window>

1 <UserControl x:Class="Demo36_WPFPrism.Views.UserControlA" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800"> 9 <Grid> 10 <TextBlock Text="用户控件A" FontSize="88"/> 11 </Grid> 12 </UserControl>

1 <UserControl x:Class="Demo36_WPFPrism.Views.UserControlB" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800"> 9 <Grid> 10 <TextBlock Text="用户控件B" FontSize="88"/> 11 </Grid> 12 </UserControl>

1 <UserControl x:Class="Demo36_WPFPrism.Views.UserControlC" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800"> 9 <Grid> 10 <TextBlock Text="用户控件C" FontSize="88"/> 11 </Grid> 12 </UserControl>
可以有效的降低ViewModel和View之间的耦合性。
①修改MainView.xaml文件,给ContenContrl区域取个名字 <ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion"/> ;
②修改App.xaml.cs文件,注册导航用的依赖;

1 protected override void RegisterTypes(IContainerRegistry containerRegistry) 2 { 3 containerRegistry.RegisterForNavigation<UserControlA>(); 4 containerRegistry.RegisterForNavigation<UserControlB>(); 5 containerRegistry.RegisterForNavigation<UserControlC>(); 6 }
③修改MainViewModel.cs文件,更新区域显示;
④以上就完成了区域的使用,下面是完整代码;

1 using System; 2 using System.Collections.Generic; 3 using System.Configuration; 4 using System.Data; 5 using System.Linq; 6 using System.Threading.Tasks; 7 using System.Windows; 8 using Demo36_WPFPrism.Views; 9 using Prism.DryIoc; 10 using Prism.Ioc; 11 12 namespace Demo36_WPFPrism 13 { 14 /// <summary> 15 /// Interaction logic for App.xaml 16 /// </summary> 17 public partial class App : PrismApplication 18 { 19 protected override Window CreateShell() 20 { 21 return Container.Resolve<MainView>(); 22 } 23 24 protected override void RegisterTypes(IContainerRegistry containerRegistry) 25 { 26 containerRegistry.RegisterForNavigation<UserControlA>("ViewA"); 27 containerRegistry.RegisterForNavigation<UserControlB>("ViewB"); 28 containerRegistry.RegisterForNavigation<UserControlC>("ViewC"); 29 } 30 } 31 }

1 <Window x:Class="Demo36_WPFPrism.Views.MainView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.Views" 7 xmlns:prism="http://prismlibrary.com/" 8 prism:ViewModelLocator.AutoWireViewModel="True" 9 mc:Ignorable="d" 10 Title="{Binding TitleText}" Height="450" Width="800"> 11 <Grid> 12 <Grid.RowDefinitions> 13 <RowDefinition Height="40"/> 14 <RowDefinition/> 15 </Grid.RowDefinitions> 16 <StackPanel Orientation="Horizontal"> 17 <Button Content="显示ViewA" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewA"/> 18 <Button Content="显示ViewB" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewB"/> 19 <Button Content="显示ViewC" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewC"/> 20 </StackPanel> 21 <ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion"/> 22 </Grid> 23 </Window>

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Demo36_WPFPrism.Views; 7 using DryIoc; 8 using Prism.Commands; 9 using Prism.DryIoc; 10 using Prism.Mvvm; 11 using Prism.Regions; 12 13 namespace Demo36_WPFPrism.ViewModels 14 { 15 public class MainViewModel : BindableBase 16 { 17 #region 属性绑定-窗口标题 18 private string _titleText="测试主页面"; 19 20 public string TitleText 21 { 22 get { return _titleText; } 23 set { _titleText = value; RaisePropertyChanged(); } 24 } 25 #endregion 26 public DelegateCommand<string> OpenCommand { get; set; } 27 28 private readonly IRegionManager _regionManager; 29 public MainViewModel(IRegionManager regionManager) 30 { 31 _regionManager = regionManager; 32 OpenCommand = new DelegateCommand<string>(Open); 33 } 34 private void Open(string obj) 35 { 36 //获取到定义的区域,给其赋值 37 _regionManager.Regions["ContentRegion"].RequestNavigate(obj); 38 } 39 } 40 }
①新建WPF类库项目Demo36-WPFPrism.ModuleA,Nuget添加程序包Prism.DryIoc;
②在Demo36-WPFPrism.ModuleA项目里新建文件夹Views,Views里新建用户控件ViewA.xaml;

1 <UserControl x:Class="Demo36_WPFPrism.ModuleA.Views.ViewA" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.ModuleA.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800"> 9 <Grid> 10 <TextBlock Text="ModuleA的ViewA" FontSize="88"/> 11 </Grid> 12 </UserControl>
③在Demo36-WPFPrism.ModuleA项目里新建类文件ModuleAProfile.cs;

1 using Demo36_WPFPrism.ModuleA.Views; 2 using Prism.Ioc; 3 using Prism.Modularity; 4 using System; 5 6 namespace Demo36_WPFPrism.ModuleA 7 { 8 public class ModuleAProfile : IModule 9 { 10 public void OnInitialized(IContainerProvider containerProvider) 11 { 12 } 13 14 public void RegisterTypes(IContainerRegistry containerRegistry) 15 { 16 containerRegistry.RegisterForNavigation<ViewA>();//注册的名字默认为ViewA 17 } 18 } 19 }
④新建WPF类库项目Demo36-WPFPrism.ModuleB,Nuget添加程序包Prism.DryIoc;
⑤在Demo36-WPFPrism.ModuleB项目里新建文件夹Views,Views里新建用户控件ViewB.xaml;

1 <UserControl x:Class="Demo36_WPFPrism.ModuleB.Views.ViewB" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.ModuleB.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800"> 9 <Grid> 10 <TextBlock Text="ModuleB的ViewB" FontSize="88"/> 11 </Grid> 12 </UserControl>
⑥在Demo36-WPFPrism.ModuleB项目里新建类文件ModuleBProfile.cs;

1 using Demo36_WPFPrism.ModuleB.Views; 2 using Prism.Ioc; 3 using Prism.Modularity; 4 using System; 5 6 namespace Demo36_WPFPrism.ModuleB 7 { 8 public class ModuleBProfile : IModule 9 { 10 public void OnInitialized(IContainerProvider containerProvider) 11 { 12 } 13 14 public void RegisterTypes(IContainerRegistry containerRegistry) 15 { 16 containerRegistry.RegisterForNavigation<ViewB>(); 17 } 18 } 19 }
⑦删除Demo36-WPFPrism项目Views文件夹下的UserControlA.xaml、UserControlB.xaml、UserControlC.xaml;删除App.xaml.cs里注册的导航依赖;
⑧把编译好的Demo36-WPFPrism.ModuleA.dll和Demo36-WPFPrism.ModuleB.dll复制到项目运行目录.\bin\Debug\net6.0-windows\Modules下;
⑨以上就完成了多模块的使用,以下是完整代码;

1 using System; 2 using System.Collections.Generic; 3 using System.Configuration; 4 using System.Data; 5 using System.Linq; 6 using System.Threading.Tasks; 7 using System.Windows; 8 using Demo36_WPFPrism.Views; 9 using Prism.DryIoc; 10 using Prism.Ioc; 11 using Prism.Modularity; 12 13 namespace Demo36_WPFPrism 14 { 15 /// <summary> 16 /// Interaction logic for App.xaml 17 /// </summary> 18 public partial class App : PrismApplication 19 { 20 protected override Window CreateShell() 21 { 22 return Container.Resolve<MainView>(); 23 } 24 25 protected override void RegisterTypes(IContainerRegistry containerRegistry) 26 { 27 } 28 protected override IModuleCatalog CreateModuleCatalog() 29 { 30 //注册使用到的模块目录 31 return new DirectoryModuleCatalog() { ModulePath = @".\Modules" }; 32 } 33 } 34 }

1 <Window x:Class="Demo36_WPFPrism.Views.MainView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.Views" 7 xmlns:prism="http://prismlibrary.com/" 8 prism:ViewModelLocator.AutoWireViewModel="True" 9 mc:Ignorable="d" 10 Title="{Binding TitleText}" Height="450" Width="800"> 11 <Grid> 12 <Grid.RowDefinitions> 13 <RowDefinition Height="40"/> 14 <RowDefinition/> 15 </Grid.RowDefinitions> 16 <StackPanel Orientation="Horizontal"> 17 <Button Content="显示ViewA" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewA"/> 18 <Button Content="显示ViewB" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewB"/> 19 </StackPanel> 20 <ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion"/> 21 </Grid> 22 </Window>

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Demo36_WPFPrism.Views; 7 using DryIoc; 8 using Prism.Commands; 9 using Prism.DryIoc; 10 using Prism.Mvvm; 11 using Prism.Regions; 12 13 namespace Demo36_WPFPrism.ViewModels 14 { 15 public class MainViewModel : BindableBase 16 { 17 #region 属性绑定-窗口标题 18 private string _titleText="测试主页面"; 19 20 public string TitleText 21 { 22 get { return _titleText; } 23 set { _titleText = value; RaisePropertyChanged(); } 24 } 25 #endregion 26 public DelegateCommand<string> OpenCommand { get; set; } 27 28 private readonly IRegionManager _regionManager; 29 public MainViewModel(IRegionManager regionManager) 30 { 31 _regionManager = regionManager; 32 OpenCommand = new DelegateCommand<string>(Open); 33 } 34 private void Open(string obj) 35 { 36 //获取到定义的区域,给其赋值 37 _regionManager.Regions["ContentRegion"].RequestNavigate(obj); 38 } 39 } 40 }
①模块Demo36_WPFPrism.ModuleA添加文件夹ViewModels,文件夹下添加ViewAViewModel.cs;

1 using Prism.Mvvm; 2 using Prism.Regions; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace Demo36_WPFPrism.ModuleA.ViewModels 10 { 11 public class ViewAViewModel : BindableBase, INavigationAware 12 { 13 private string _titleText; 14 15 public string TitleText 16 { 17 get { return _titleText; } 18 set { _titleText = value;RaisePropertyChanged(); } 19 } 20 21 public ViewAViewModel() 22 { 23 24 } 25 26 /// <summary> 27 /// 每次重新导航的时候,是否重用原来的实例 28 /// </summary> 29 /// <param name="navigationContext"></param> 30 /// <returns></returns> 31 public bool IsNavigationTarget(NavigationContext navigationContext) 32 { 33 return true; 34 } 35 36 public void OnNavigatedFrom(NavigationContext navigationContext) 37 { 38 } 39 40 public void OnNavigatedTo(NavigationContext navigationContext) 41 { 42 if(navigationContext.Parameters.Keys.Contains("TitleText")) 43 TitleText = navigationContext.Parameters.GetValue<string>("TitleText"); 44 } 45 } 46 }
②更新模块Demo36_WPFPrism.ModuleA的Views文件夹下ViewA.xaml;

1 <UserControl x:Class="Demo36_WPFPrism.ModuleA.Views.ViewA" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.ModuleA.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800"> 9 <Grid> 10 <TextBlock Text="ModuleA的ViewA" FontSize="88"/> 11 <TextBlock Text="{Binding TitleText}" FontSize="108"/> 12 </Grid> 13 </UserControl>
③更新模块Demo36_WPFPrism.ModuleA下的ModuleAProfile.cs;

1 using Demo36_WPFPrism.ModuleA.ViewModels; 2 using Demo36_WPFPrism.ModuleA.Views; 3 using Prism.Ioc; 4 using Prism.Modularity; 5 using System; 6 7 namespace Demo36_WPFPrism.ModuleA 8 { 9 public class ModuleAProfile : IModule 10 { 11 public void OnInitialized(IContainerProvider containerProvider) 12 { 13 } 14 15 public void RegisterTypes(IContainerRegistry containerRegistry) 16 { 17 containerRegistry.RegisterForNavigation<ViewA, ViewAViewModel>();//注册的名字默认为ViewA 18 } 19 } 20 }
④编译项目Demo36_WPFPrism.ModuleA后,把Demo36-WPFPrism.ModuleA.dll复制到项目运行目录.\bin\Debug\net6.0-windows\Modules下;
⑤更新应用程序Demo36-WPFPrism文件夹ViewModels下MainViewModel.cs文件,传递参数给ModuleA;

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Demo36_WPFPrism.Views; 7 using DryIoc; 8 using Prism.Commands; 9 using Prism.DryIoc; 10 using Prism.Mvvm; 11 using Prism.Regions; 12 13 namespace Demo36_WPFPrism.ViewModels 14 { 15 public class MainViewModel : BindableBase 16 { 17 #region 属性绑定-窗口标题 18 private string _titleText="测试主页面"; 19 20 public string TitleText 21 { 22 get { return _titleText; } 23 set { _titleText = value; RaisePropertyChanged(); } 24 } 25 #endregion 26 public DelegateCommand<string> OpenCommand { get; set; } 27 28 private readonly IRegionManager _regionManager; 29 public MainViewModel(IRegionManager regionManager) 30 { 31 _regionManager = regionManager; 32 OpenCommand = new DelegateCommand<string>(Open); 33 } 34 private void Open(string obj) 35 { 36 NavigationParameters parameters = new NavigationParameters(); 37 parameters.Add("TitleText", "模块A的标题"); 38 //获取到定义的区域,给其赋值 39 _regionManager.Regions["ContentRegion"].RequestNavigate(obj); 40 } 41 } 42 }
⑥以上就完成了导航功能传递参数;
①更新模块Demo36_WPFPrism.ModuleA添加文件夹ViewModels,文件夹下添加ViewAViewModel.cs,继承INavigationAware更改为IConfirmNavigationRequest;
②实现拦截函数

1 using Prism.Mvvm; 2 using Prism.Regions; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 using System.Windows; 9 10 namespace Demo36_WPFPrism.ModuleA.ViewModels 11 { 12 public class ViewAViewModel : BindableBase, IConfirmNavigationRequest 13 { 14 private string _titleText; 15 16 public string TitleText 17 { 18 get { return _titleText; } 19 set { _titleText = value;RaisePropertyChanged(); } 20 } 21 22 public ViewAViewModel() 23 { 24 25 } 26 27 /// <summary> 28 /// 每次重新导航的时候,是否重用原来的实例 29 /// </summary> 30 /// <param name="navigationContext"></param> 31 /// <returns></returns> 32 public bool IsNavigationTarget(NavigationContext navigationContext) 33 { 34 return true; 35 } 36 /// <summary> 37 /// 导航到别的页面前触发,可以用来拦截请求 38 /// </summary> 39 /// <param name="navigationContext"></param> 40 public void OnNavigatedFrom(NavigationContext navigationContext) 41 { 42 } 43 44 public void OnNavigatedTo(NavigationContext navigationContext) 45 { 46 if(navigationContext.Parameters.Keys.Contains("TitleText")) 47 TitleText = navigationContext.Parameters.GetValue<string>("TitleText"); 48 } 49 /// <summary> 50 /// 拦截导航跳转 51 /// </summary> 52 /// <param name="navigationContext"></param> 53 /// <param name="continuationCallback"></param> 54 /// <exception cref="NotImplementedException"></exception> 55 public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback) 56 { 57 bool navigationResult = true; 58 if (MessageBox.Show("确认导航?", "温馨提示", MessageBoxButton.YesNo) == MessageBoxResult.No) 59 { 60 navigationResult = false; 61 } 62 continuationCallback(navigationResult); 63 } 64 } 65 }
③编译项目Demo36_WPFPrism.ModuleA后,把Demo36-WPFPrism.ModuleA.dll复制到项目运行目录.\bin\Debug\net6.0-windows\Modules下;
④以上就完成了导航的拦截,可以测试以下;
①更新应用程序Demo36-WPFPrism文件夹ViewModels下MainViewModel.cs文件;

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Demo36_WPFPrism.Views; 7 using DryIoc; 8 using Prism.Commands; 9 using Prism.DryIoc; 10 using Prism.Mvvm; 11 using Prism.Regions; 12 13 namespace Demo36_WPFPrism.ViewModels 14 { 15 public class MainViewModel : BindableBase 16 { 17 #region 属性绑定-窗口标题 18 private string _titleText="测试主页面"; 19 20 public string TitleText 21 { 22 get { return _titleText; } 23 set { _titleText = value; RaisePropertyChanged(); } 24 } 25 #endregion 26 public DelegateCommand<string> OpenCommand { get; set; } 27 public DelegateCommand BackCommand { get; set; } 28 29 private readonly IRegionManager _regionManager; 30 private IRegionNavigationJournal _journal; 31 public MainViewModel(IRegionManager regionManager) 32 { 33 _regionManager = regionManager; 34 OpenCommand = new DelegateCommand<string>(Open); 35 BackCommand = new DelegateCommand(Back); 36 } 37 private void Open(string obj) 38 { 39 NavigationParameters parameters = new NavigationParameters(); 40 parameters.Add("TitleText", "模块A的标题"); 41 //获取到定义的区域,给其赋值 42 _regionManager.Regions["ContentRegion"].RequestNavigate(obj, callback=> { 43 if ((bool)callback.Result) 44 { 45 _journal = callback.Context.NavigationService.Journal; 46 } 47 },parameters); 48 } 49 private void Back() 50 { 51 if (_journal.CanGoBack) 52 { 53 _journal.GoBack(); 54 //_journal.GoForward(); 55 //_journal.Clear(); 56 } 57 } 58 } 59 }
②以上就完成了导航日志记录功能;
①更新模块Demo36_WPFPrism.ModuleA添加文件夹Views,文件夹下添加用户ViewC.xaml,用来做弹出模态框的页面;

1 <UserControl x:Class="Demo36_WPFPrism.ModuleA.Views.ViewC" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.ModuleA.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800"> 9 <Grid> 10 <Grid.RowDefinitions> 11 <RowDefinition Height="auto"/> 12 <RowDefinition Height="auto"/> 13 <RowDefinition Height="auto"/> 14 <RowDefinition/> 15 </Grid.RowDefinitions> 16 <StackPanel Grid.Row="1" Orientation="Horizontal"> 17 <TextBlock Text="用户名:" FontSize="28"/> 18 <TextBox Text="{Binding UserName}" FontSize="28" Width="180"/> 19 </StackPanel> 20 <StackPanel Grid.Row="2" Orientation="Horizontal"> 21 <TextBlock Text="密码:" FontSize="28"/> 22 <TextBox Text="{Binding PWD}" FontSize="28" Width="208"/> 23 </StackPanel> 24 <Button Grid.Row="0" Content="关闭按钮" Command="{Binding CloseDialogCommand}"/> 25 </Grid> 26 </UserControl>
②更新模块Demo36_WPFPrism.ModuleA添加文件夹ViewModels,文件夹下添加ViewCViewModel.cs,做弹出模态框的ViewModel,需要继承基类BindableBase,实现接口IDialogAware;

1 using Prism.Commands; 2 using Prism.Events; 3 using Prism.Mvvm; 4 using Prism.Services.Dialogs; 5 using System; 6 using System.Collections.Generic; 7 using System.Linq; 8 using System.Text; 9 using System.Threading.Tasks; 10 11 namespace Demo36_WPFPrism.ModuleA.ViewModels 12 { 13 public class ViewCViewModel : BindableBase, IDialogAware 14 { 15 #region 属性-用户名 16 private string _userName; 17 18 public string UserName 19 { 20 get { return _userName; } 21 set { _userName = value; RaisePropertyChanged(); } 22 } 23 #endregion 24 #region 属性-密码 25 private string _pwd; 26 public string PWD 27 { 28 get { return _pwd; } 29 set { _pwd = value; RaisePropertyChanged(); } 30 } 31 #endregion 32 33 public DelegateCommand CloseDialogCommand { get; set; } 34 public ViewCViewModel() 35 { 36 CloseDialogCommand = new DelegateCommand(CloseDialog); 37 } 38 39 private void CloseDialog() 40 { 41 DialogParameters dialogParameters = new DialogParameters(); 42 dialogParameters.Add("UserName", UserName); 43 dialogParameters.Add("PWD", PWD); 44 //返回模态框操作状态及参数 45 RequestClose?.Invoke(new DialogResult(ButtonResult.OK, dialogParameters)); 46 47 } 48 49 public string Title { get; set; } 50 51 public event Action<IDialogResult> RequestClose; 52 53 public bool CanCloseDialog() 54 { 55 return true; 56 } 57 58 59 public void OnDialogClosed() 60 { 61 //注意,提交模态框返回参数不能使用这个退出,此函数中RequestClose为null 62 } 63 /// <summary> 64 /// 模态框打开的时候带入参数显示 65 /// </summary> 66 /// <param name="parameters"></param> 67 /// <exception cref="NotImplementedException"></exception> 68 public void OnDialogOpened(IDialogParameters parameters) 69 { 70 Title=parameters.GetValue<string>("TitleText"); 71 } 72 } 73 }
③更新模块Demo36_WPFPrism.ModuleA下的ModuleAProfile.cs,添加对模态框ViewC的注册;

1 using Demo36_WPFPrism.ModuleA.ViewModels; 2 using Demo36_WPFPrism.ModuleA.Views; 3 using Prism.Ioc; 4 using Prism.Modularity; 5 using System; 6 7 namespace Demo36_WPFPrism.ModuleA 8 { 9 public class ModuleAProfile : IModule 10 { 11 public void OnInitialized(IContainerProvider containerProvider) 12 { 13 } 14 15 public void RegisterTypes(IContainerRegistry containerRegistry) 16 { 17 containerRegistry.RegisterForNavigation<ViewA, ViewAViewModel>();//注册的名字默认为ViewA 18 containerRegistry.RegisterDialog<ViewC, ViewCViewModel>();//注册模态框用户控件 19 } 20 } 21 }
④更新应用程序Demo36-WPFPrism文件夹Views下MainView.xaml文件,添加打开模态框的按钮及其绑定命令;

1 <Window x:Class="Demo36_WPFPrism.Views.MainView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.Views" 7 xmlns:prism="http://prismlibrary.com/" 8 prism:ViewModelLocator.AutoWireViewModel="True" 9 mc:Ignorable="d" 10 Title="{Binding TitleText}" Height="450" Width="800"> 11 <Grid> 12 <Grid.RowDefinitions> 13 <RowDefinition Height="40"/> 14 <RowDefinition/> 15 </Grid.RowDefinitions> 16 <StackPanel Orientation="Horizontal"> 17 <Button Content="显示ViewA" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewA"/> 18 <Button Content="显示ViewB" Margin="0,0,10,0" Command="{Binding OpenCommand}" CommandParameter="ViewB"/> 19 <Button Content="回退" Margin="0,0,10,0" Command="{Binding BackCommand}"/> 20 <Button Content="打开模态框ViewC" Margin="0,0,10,0" Command="{Binding OpenDialogCommand}" CommandParameter="ViewC"/> 21 </StackPanel> 22 <ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion"/> 23 </Grid> 24 </Window>
⑤更新应用程序Demo36-WPFPrism文件夹ViewModels下MainViewModel.cs文件,添加按钮命令实现;

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using Demo36_WPFPrism.Views; 8 using DryIoc; 9 using Prism.Commands; 10 using Prism.DryIoc; 11 using Prism.Mvvm; 12 using Prism.Regions; 13 using Prism.Services.Dialogs; 14 15 namespace Demo36_WPFPrism.ViewModels 16 { 17 public class MainViewModel : BindableBase 18 { 19 #region 属性绑定-窗口标题 20 private string _titleText="测试主页面"; 21 22 public string TitleText 23 { 24 get { return _titleText; } 25 set { _titleText = value; RaisePropertyChanged(); } 26 } 27 #endregion 28 public DelegateCommand<string> OpenCommand { get; set; } 29 public DelegateCommand BackCommand { get; set; } 30 public DelegateCommand<string> OpenDialogCommand { get; set; } 31 32 private readonly IRegionManager _regionManager; 33 private IRegionNavigationJournal _journal; 34 private readonly IDialogService _dialogService; 35 public MainViewModel(IRegionManager regionManager, IDialogService dialogService) 36 { 37 _regionManager = regionManager; 38 OpenCommand = new DelegateCommand<string>(Open); 39 BackCommand = new DelegateCommand(Back); 40 _dialogService = dialogService; 41 OpenDialogCommand =new DelegateCommand<string>(OpenDialog); 42 } 43 private void Open(string obj) 44 { 45 NavigationParameters parameters = new NavigationParameters(); 46 parameters.Add("TitleText", "模块A的标题"); 47 //获取到定义的区域,给其赋值 48 _regionManager.Regions["ContentRegion"].RequestNavigate(obj, callback=> { 49 if ((bool)callback.Result) 50 { 51 _journal = callback.Context.NavigationService.Journal; 52 } 53 },parameters); 54 } 55 private void Back() 56 { 57 if (_journal.CanGoBack) 58 { 59 _journal.GoBack(); 60 //_journal.GoForward(); 61 //_journal.Clear(); 62 } 63 } 64 65 private void OpenDialog(string obj) 66 { 67 DialogParameters parameters = new DialogParameters(); 68 parameters.Add("TitleText", "传递到Dialog的参数"); 69 _dialogService.ShowDialog(obj,parameters, callback => 70 { 71 72 }); 73 } 74 } 75 }
⑥编译项目Demo36_WPFPrism.ModuleA后,把Demo36-WPFPrism.ModuleA.dll复制到项目运行目录.\bin\Debug\net6.0-windows\Modules下;
⑦以上就完成了模态框弹窗的注册使用;
①添加WPF类库项目Demo36-WPFPrism.Event添加消息类StringMessageEvent.cs,Nuget引入包Prism.DryIoc,继承自泛型字符串消息基类PubSubEvent<string>,消息也可以是其他类型的,比如:UserInfoMessage类型的;

1 using Prism.Events; 2 using System; 3 4 namespace Demo36_WPFPrism.Event 5 { 6 public class StringMessageEvent : PubSubEvent<string> 7 { 8 9 } 10 }
②更新应用程序Demo36-WPFPrism文件夹Views下MainView.xaml.cs文件,构造函数注入IEventAggregator接口,并实现消息订阅功能;

1 using Demo36_WPFPrism.Event; 2 using Prism.Events; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 using System.Windows; 9 using System.Windows.Controls; 10 using System.Windows.Data; 11 using System.Windows.Documents; 12 using System.Windows.Input; 13 using System.Windows.Media; 14 using System.Windows.Media.Imaging; 15 using System.Windows.Shapes; 16 17 namespace Demo36_WPFPrism.Views 18 { 19 /// <summary> 20 /// MainView.xaml 的交互逻辑 21 /// </summary> 22 public partial class MainView : Window 23 { 24 public MainView(IEventAggregator eventAggregator) 25 { 26 InitializeComponent(); 27 eventAggregator.GetEvent<StringMessageEvent>().Subscribe(arg => { MessageBox.Show($"接收到消息:{arg}"); }); 28 } 29 } 30 }
③更新模块Demo36_WPFPrism.ModuleA文件夹Views下ViewC.xaml类,添加发布消息的按钮和命令委托绑定;

1 <UserControl x:Class="Demo36_WPFPrism.ModuleA.Views.ViewC" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Demo36_WPFPrism.ModuleA.Views" 7 mc:Ignorable="d" 8 d:DesignHeight="450" d:DesignWidth="800"> 9 <Grid> 10 <Grid.RowDefinitions> 11 <RowDefinition Height="auto"/> 12 <RowDefinition Height="auto"/> 13 <RowDefinition Height="auto"/> 14 <RowDefinition/> 15 </Grid.RowDefinitions> 16 <StackPanel Grid.Row="1" Orientation="Horizontal"> 17 <TextBlock Text="用户名:" FontSize="28"/> 18 <TextBox Text="{Binding UserName}" FontSize="28" Width="180"/> 19 </StackPanel> 20 <StackPanel Grid.Row="2" Orientation="Horizontal"> 21 <TextBlock Text="密码:" FontSize="28"/> 22 <TextBox Text="{Binding PWD}" FontSize="28" Width="208"/> 23 </StackPanel> 24 <StackPanel Grid.Row="0" > 25 <Button Content="关闭按钮" Command="{Binding CloseDialogCommand}"/> 26 <Button Content="发布消息" Command="{Binding PublishCommand}"/> 27 </StackPanel> 28 </Grid> 29 </UserControl>
④更新模块Demo36_WPFPrism.ModuleA文件夹ViewModels下ViewCViewModel.cs类,构造函数注入IEventAggregator接口,在确定按钮里添加消息发布的代码;

1 using Demo36_WPFPrism.Event; 2 using Prism.Commands; 3 using Prism.Events; 4 using Prism.Mvvm; 5 using Prism.Services.Dialogs; 6 using System; 7 using System.Collections.Generic; 8 using System.Linq; 9 using System.Text; 10 using System.Threading.Tasks; 11 12 namespace Demo36_WPFPrism.ModuleA.ViewModels 13 { 14 public class ViewCViewModel : BindableBase, IDialogAware 15 { 16 #region 属性-用户名 17 private string _userName; 18 19 public string UserName 20 { 21 get { return _userName; } 22 set { _userName = value; RaisePropertyChanged(); } 23 } 24 #endregion 25 #region 属性-密码 26 private string _pwd; 27 public string PWD 28 { 29 get { return _pwd; } 30 set { _pwd = value; RaisePropertyChanged(); } 31 } 32 #endregion 33 34 public DelegateCommand CloseDialogCommand { get; set; } 35 private readonly IEventAggregator _eventAggregator; 36 public DelegateCommand PublishCommand { get; set; } 37 public ViewCViewModel(IEventAggregator eventAggregator) 38 { 39 CloseDialogCommand = new DelegateCommand(CloseDialog); 40 _eventAggregator = eventAggregator; 41 PublishCommand = new DelegateCommand(Publish); 42 } 43 44 private void CloseDialog() 45 { 46 DialogParameters dialogParameters = new DialogParameters(); 47 dialogParameters.Add("UserName", UserName); 48 dialogParameters.Add("PWD", PWD); 49 //返回模态框操作状态及参数 50 RequestClose?.Invoke(new DialogResult(ButtonResult.OK, dialogParameters)); 51 52 } 53 54 public string Title { get; set; } 55 56 public event Action<IDialogResult> RequestClose; 57 58 public bool CanCloseDialog() 59 { 60 return true; 61 } 62 63 64 public void OnDialogClosed() 65 { 66 //注意,提交模态框返回参数不能使用这个退出,此函数中RequestClose为null 67 } 68 /// <summary> 69 /// 模态框打开的时候带入参数显示 70 /// </summary> 71 /// <param name="parameters"></param> 72 /// <exception cref="NotImplementedException"></exception> 73 public void OnDialogOpened(IDialogParameters parameters) 74 { 75 Title=parameters.GetValue<string>("TitleText"); 76 } 77 78 public void Publish() 79 { 80 _eventAggregator.GetEvent<StringMessageEvent>().Publish("ViewCViewModel发布消息"); 81 } 82 } 83 }
⑤编译项目Demo36_WPFPrism.ModuleA后,把Demo36-WPFPrism.ModuleA.dll复制到项目运行目录.\bin\Debug\net6.0-windows\Modules下;
⑥以上就完成了消息的发布订阅功能;
https://github.com/PrismLibrary/Prism#core-packages
https://www.cnblogs.com/zh7791
https://prismlibrary.com/docs/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?