当前位置: 首页 > news >正文

Prism框架核心对象全解析

Prism作为.NET生态中成熟的MVVM框架,其核心能力围绕一系列基础对象构建。本文将按照数据与行为、IoC容器、消息总线、弹窗、区域化、模块化的逻辑,全面解析Prism框架的核心对象及其使用方法,为开发者提供体系化的学习指南。

一、数据与行为对象

数据与行为对象是Prism实现MVVM模式的基础,负责数据绑定和命令封装,实现视图与视图模型的解耦。

1. BindableBase:数据绑定的基础

作用与特性

`BindableBase`是Prism提供的视图模型基类,实现了`INotifyPropertyChanged`接口,用于通知UI数据属性的变化,是数据绑定的核心支撑。其核心特性包括:

  • 自动触发属性变更通知,减少重复代码

  • 支持属性值比较,避免无效通知

  • 所有视图模型建议继承此类以实现数据绑定

关键方法
  • SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null):设置属性值并触发变更通知,当新值与旧值不同时才会通知UI。

  • RaisePropertyChanged([CallerMemberName] string propertyName = null):手动触发指定属性的变更通知,适用于计算属性等场景。

使用示例
public class UserViewModel : BindableBase
{private string _userName;private int _age;// 基础属性绑定public string UserName{get => _userName;set => SetProperty(ref _userName, value);}// 计算属性(需手动触发通知)public string UserInfo => $"姓名:{UserName},年龄:{_age}";public int Age{get => _age;set {if (SetProperty(ref _age, value)){// 当Age变化时,触发UserInfo的变更通知RaisePropertyChanged(nameof(UserInfo));}}}
}

2. DelegateCommand/DelegateCommand<T>:行为的封装

作用与特性

`DelegateCommand`是Prism对`ICommand`接口的实现,用于封装视图中的用户交互行为(如按钮点击),实现行为与视图的解耦。其特性包括:

  • 支持无参数和带参数的命令

  • 内置命令可执行状态管理(`CanExecute`)

  • 支持命令状态变更通知(`RaiseCanExecuteChanged`)

关键方法
  • DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod = null):无参数命令构造函数,接收执行逻辑和可执行状态判断函数。

  • DelegateCommand<T>(Action<T> executeMethod, Func<T, bool> canExecuteMethod = null):带参数命令构造函数。

  • RaiseCanExecuteChanged():手动触发命令可执行状态变更,更新UI控件的启用/禁用状态。

使用示例
无参数命令
public class MainViewModel : BindableBase
{public DelegateCommand RefreshCommand { get; }public MainViewModel(){// 初始化无参数命令RefreshCommand = new DelegateCommand(RefreshData, CanRefresh);}private void RefreshData(){// 刷新数据逻辑}private bool CanRefresh(){// 命令可执行条件(如数据未正在刷新)return !_isRefreshing;}// 当可执行条件变化时,触发状态更新private void OnRefreshStatusChanged(){RefreshCommand.RaiseCanExecuteChanged();}
}
带参数的命令
public class UserViewModel : BindableBase
{public DelegateCommand<string> DeleteUserCommand { get; }public UserViewModel(){// 带参数命令(参数为用户ID)DeleteUserCommand = new DelegateCommand<string>(DeleteUser, CanDeleteUser);}private void DeleteUser(string userId){// 根据用户ID删除用户逻辑}private bool CanDeleteUser(string userId){// 可执行条件(如用户ID不为空且当前用户有删除权限)return !string.IsNullOrEmpty(userId) && _hasDeletePermission;}
}
在XAML中绑定命令
<!-- 无参数命令绑定 -->
<Button Content="刷新数据" Command="{Binding RefreshCommand}" /><!-- 带参数命令绑定(参数为文本框内容) -->
<StackPanel><TextBox x:Name="UserIdTextBox" /><Button Content="删除用户" Command="{Binding DeleteUserCommand}" CommandParameter="{Binding Text, ElementName=UserIdTextBox}" />
</StackPanel>

二、Prism框架中的IoC(控制反转)容器

IoC容器是Prism实现依赖注入的核心,负责服务的注册与解析,降低组件间的耦合度,提升代码的可测试性和可维护性。

1. 核心接口与配置

1.1 容器配置入口

Prism应用的容器配置主要在`App.xaml.cs`的`RegisterTypes`方法中进行,该方法在应用启动时执行,用于注册所有服务和视图模型:

public partial class App : PrismApplication
{protected override void RegisterTypes(IContainerRegistry containerRegistry){// 在此注册服务和视图模型containerRegistry.Register<IUserService, UserService>();containerRegistry.RegisterForNavigation<MainView, MainViewModel>();}// 其他方法(如CreateShell)...
}
1.2 关键接口
  • IContainerRegistry:用于注册服务的接口,提供`Register`、`RegisterSingleton`等注册方法,仅在应用初始化阶段使用。

  • IContainerProvider:用于解析服务的接口,提供`Resolve`方法,在运行时通过依赖注入获取。

  • IContainerExtension:容器扩展接口,封装了底层容器(如DryIoc、Unity)的具体实现。

2. 服务注册方式

2.1 基础注册
// 1. 接口与实现类注册(瞬时生命周期)
containerRegistry.Register<IProductService, ProductService>();// 2. 具体类型注册(无需接口)
containerRegistry.Register<UserViewModel>();// 3. 导航视图注册(关联视图与视图模型)
containerRegistry.RegisterForNavigation<ProductView, ProductViewModel>();
2.2 生命周期控制

Prism支持三种核心服务生命周期,适用于不同场景:

// 1. 单例(Singleton):整个应用生命周期唯一实例
containerRegistry.RegisterSingleton<IConfigurationService, ConfigurationService>();// 2. 瞬时(Transient):每次解析创建新实例
containerRegistry.Register<IDataContext, DataContext>();// 3. 作用域(Scoped):在指定作用域内唯一(如导航作用域)
containerRegistry.RegisterScoped<IUnitOfWork, UnitOfWork>();

3. 依赖注入方式

3.1 构造函数注入(推荐)

构造函数注入是Prism推荐的注入方式,通过构造函数参数声明依赖,容器自动解析并注入:

public class ProductViewModel : BindableBase
{private readonly IProductService _productService;// 构造函数注入服务public ProductViewModel(IProductService productService){_productService = productService;LoadProducts();}private void LoadProducts(){var products = _productService.GetAllProducts();// 处理产品数据}
}
3.2 属性注入(需谨慎)

属性注入通过标记`[Dependency]`特性实现,适用于可选依赖场景,但会增加代码耦合度,需谨慎使用:

public class ProductViewModel : BindableBase
{// 属性注入(可选依赖)[Dependency]public ILoggerService LoggerService { get; set; }public void LogOperation(string message){LoggerService?.Log(message); // 需判断服务是否注入}
}

4. 模块化中的IoC

模块中的服务注册通过`IModule`接口的`RegisterTypes`方法实现,模块内注册的服务全局可见:

public class ProductModule : IModule
{public void RegisterTypes(IContainerRegistry containerRegistry){// 模块内注册服务containerRegistry.Register<IProductService, ProductService>();}public void OnInitialized(IContainerProvider containerProvider){// 模块初始化逻辑}
}

5. 解析服务

通过`IContainerProvider`解析服务,通常在视图模型或模块初始化时使用:

public class MainViewModel : BindableBase
{public MainViewModel(IContainerProvider containerProvider){// 解析服务var userService = containerProvider.Resolve<IUserService>();var users = userService.GetUsers();}
}

6. 高级功能

6.1 命名注册

当同一接口有多个实现时,可通过命名注册区分:

// 命名注册不同实现
containerRegistry.Register<IReportService, PdfReportService>(name: "PdfReport");
containerRegistry.Register<IReportService, ExcelReportService>(name: "ExcelReport");// 按名称解析
var pdfReport = containerProvider.Resolve<IReportService>(name: "PdfReport");
6.2 延迟加载与工厂模式

通过工厂模式实现服务的延迟加载,适用于服务创建成本较高的场景:

// 注册工厂
containerRegistry.Register<Func<string, IReportService>>(factory: provider => reportType =>{return reportType switch{"Pdf" => provider.Resolve<IReportService>("PdfReport"),"Excel" => provider.Resolve<IReportService>("ExcelReport"),_ => throw new ArgumentException("不支持的报告类型")};});// 使用工厂
public class ReportViewModel : BindableBase
{public ReportViewModel(Func<string, IReportService> reportFactory){// 延迟创建Pdf报告服务var pdfReport = reportFactory("Pdf");}
}

三、Prism框架中的消息对象(事件总线)

Prism的消息对象(事件总线)通过`EventAggregator`实现,用于组件间(尤其是跨模块)的解耦通信,避免直接引用导致的耦合。

1. 核心组件

  • IEventAggregator:事件聚合器接口,用于获取事件实例和管理事件发布订阅。

  • PubSubEvent<T>:泛型事件类,T为事件参数类型,所有自定义事件需继承此类。

  • SubscriptionToken:订阅令牌,用于取消事件订阅。

2. 使用流程

2.1 定义事件类
// 1. 无参数事件
public class AppStartedEvent : PubSubEvent { }// 2. 带参数事件(事件参数为自定义实体)
public class OrderStatusChangedEvent : PubSubEvent<OrderStatusEventArgs> { }// 事件参数实体
public class OrderStatusEventArgs
{public string OrderId { get; set; }public string Status { get; set; }public DateTime ChangedTime { get; set; }
}
2.2 发布事件

通过`IEventAggregator`获取事件实例并发布:

public class OrderService
{private readonly IEventAggregator _eventAggregator;public OrderService(IEventAggregator eventAggregator){_eventAggregator = eventAggregator;}public void UpdateOrderStatus(string orderId, string status){// 更新订单状态逻辑// 发布事件_eventAggregator.GetEvent<OrderStatusChangedEvent>().Publish(new OrderStatusEventArgs{OrderId = orderId,Status = status,ChangedTime = DateTime.Now});}
}
2.3 订阅事件
public class OrderViewModel : BindableBase, IDisposable
{private readonly IEventAggregator _eventAggregator;private SubscriptionToken _subscriptionToken;public OrderViewModel(IEventAggregator eventAggregator){_eventAggregator = eventAggregator;// 订阅事件_subscriptionToken = _eventAggregator.GetEvent<OrderStatusChangedEvent>().Subscribe(OnOrderStatusChanged);}private void OnOrderStatusChanged(OrderStatusEventArgs args){// 处理订单状态变化逻辑Console.WriteLine($"订单{args.OrderId}状态变更为:{args.Status}");}// 取消订阅(避免内存泄漏)public void Dispose(){if (_subscriptionToken != null){_eventAggregator.GetEvent<OrderStatusChangedEvent>().Unsubscribe(_subscriptionToken);}}
}

3. 高级配置

3.1 订阅选项

`Subscribe`方法提供多个参数,用于配置订阅行为,各参数应用场景如下:

_eventAggregator.GetEvent<OrderStatusChangedEvent>().Subscribe(action: OnOrderStatusChanged,          // 事件处理回调threadOption: ThreadOption.UIThread,   // 线程选项keepSubscriberReferenceAlive: false,   // 引用生命周期filter: args => args.Status == "Completed" // 消息过滤条件);
各参数的应用场景总结
  • threadOptionThreadOption.PublisherThread:在发布者线程执行回调(默认),适用于非UI操作。

  • ThreadOption.UIThread:在UI线程执行回调,适用于更新UI的场景。

  • ThreadOption.BackgroundThread:在后台线程执行回调,适用于耗时操作。

keepSubscriberReferenceAlivetrue:强引用订阅者,需手动取消订阅,否则内存泄漏。

false:弱引用订阅者,订阅者释放后自动取消订阅(推荐)。

filter:消息过滤函数,仅当返回true时执行回调,适用于只关注特定消息的场景。

详细使用教程
  1. 主要委托方法(回调逻辑):回调方法参数类型需与事件参数类型一致,用于处理事件数据,如`OnOrderStatusChanged(OrderStatusEventArgs args)`。

  2. 消息过滤条件(filter):例如仅订阅状态为“已完成”的订单事件,减少无效回调。

  3. 消息委托的引用方式(keepSubscriberReferenceAlive):推荐设为`false`,结合`IDisposable`接口确保订阅及时取消。

  4. 多线程状态控制(ThreadOption):更新UI时必须设为`UIThread`,避免跨线程操作异常。

3.2 取消订阅

取消订阅有三种方式:

// 1. 通过SubscriptionToken取消(推荐)
_eventAggregator.GetEvent<OrderStatusChangedEvent>().Unsubscribe(_subscriptionToken);// 2. 通过回调方法取消
_eventAggregator.GetEvent<OrderStatusChangedEvent>().Unsubscribe(OnOrderStatusChanged);// 3. 取消所有订阅
_eventAggregator.GetEvent<OrderStatusChangedEvent>().UnsubscribeAll();

4. 实际应用场景

4.1 跨模块通信

模块A和模块B无直接引用,通过事件总线传递数据,如订单模块通知库存模块更新库存。

4.2 全局状态通知

用户登录状态变化后,通过事件通知所有模块更新UI(如显示/隐藏登录按钮)。

4.3 弹窗交互

弹窗关闭时发布事件,通知调用方弹窗结果(如确认/取消操作)。

四、Prism框架中的弹窗对象

Prism的弹窗对象通过`IDialogService`实现,提供统一的弹窗管理能力,支持弹窗传参、结果回调和自定义样式,符合MVVM模式。

1. 核心组件

1.1 IDialogService

弹窗服务接口,用于显示和管理弹窗,提供`Show`、`ShowDialog`等方法。

1.2 IDialogAware

弹窗视图模型需实现的接口,用于处理弹窗的打开、关闭和参数传递:

  • OnDialogOpened(IDialogParameters parameters):弹窗打开时执行,接收传入参数。

  • OnDialogClosed(IDialogResult result):弹窗关闭时执行,处理关闭结果。

  • CanCloseDialog():判断弹窗是否可关闭(如验证未保存的更改)。

  • RequestClose:事件,用于通知弹窗服务关闭弹窗。

2. 创建弹窗的完整流程

2.1 定义弹窗视图(View)
<!-- DialogView.xaml -->
<UserControl x:Class="PrismDemo.Views.DialogView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:prism="http://prismlibrary.com/"prism:ViewModelLocator.AutowireViewModel="True"><Grid Width="300" Height="200" Background="White"><StackPanel Margin="20"><TextBlock Text="{Binding Message}" /><StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,20,0,0"><Button Content="取消" Command="{Binding CancelCommand}" Margin="0,0,10,0" /><Button Content="确认" Command="{Binding ConfirmCommand}" /></StackPanel></StackPanel></Grid>
</UserControl>
2.2 实现弹窗ViewModel
public class DialogViewModel : BindableBase, IDialogAware
{private string _message;public string Message{get => _message;set => SetProperty(ref _message, value);}public DelegateCommand ConfirmCommand { get; }public DelegateCommand CancelCommand { get; }public DialogViewModel(){ConfirmCommand = new DelegateCommand(OnConfirm);CancelCommand = new DelegateCommand(OnCancel);}private void OnConfirm(){// 构造返回结果var parameters = new DialogParameters { { "Result", true } };RequestClose?.Invoke(new DialogResult(ButtonResult.OK, parameters));}private void OnCancel(){RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel));}// IDialogAware接口实现public event Action<IDialogResult> RequestClose;public bool CanCloseDialog(){// 弹窗可关闭条件(如无未保存更改)return true;}public void OnDialogClosed(IDialogResult result){// 弹窗关闭后的清理逻辑}public void OnDialogOpened(IDialogParameters parameters){// 接收传入参数if (parameters.TryGetValue("Message", out string message)){Message = message;}}
}
2.3 注册弹窗

在`App.xaml.cs`或模块中注册弹窗:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{// 注册弹窗(视图与视图模型关联)containerRegistry.RegisterDialog<DialogView, DialogViewModel>();
}

3. 触发弹窗显示

3.1 在ViewModel中调用弹窗

通过`IDialogService`显示弹窗并处理结果:

public class MainViewModel : BindableBase
{private readonly IDialogService _dialogService;public DelegateCommand ShowDialogCommand { get; }public MainViewModel(IDialogService dialogService){_dialogService = dialogService;ShowDialogCommand = new DelegateCommand(ShowDialog);}private void ShowDialog(){// 构造弹窗参数var parameters = new DialogParameters();parameters.Add("Message", "请确认是否执行此操作?");// 显示弹窗(模态)_dialogService.ShowDialog("DialogView", parameters, result =>{if (result.Result == ButtonResult.OK){// 处理确认结果bool dialogResult = result.Parameters.GetValue<bool>("Result");Console.WriteLine($"弹窗结果:{dialogResult}");}});}
}
3.2 直接通过View触发(不推荐,破坏MVVM)

不推荐在View的后台代码中直接调用弹窗,会破坏MVVM的职责分离原则:

// 不推荐的写法
public partial class MainView : UserControl
{public MainView(IDialogService dialogService){InitializeComponent();// 直接在View中调用弹窗(破坏MVVM)dialogService.ShowDialog("DialogView");}
}

4. 高级功能

4.1 自定义弹窗样式

通过`DialogWindow`自定义弹窗样式,如标题栏、边框等:

<!-- 自定义弹窗窗口 -->
<prism:DialogWindow x:Class="PrismDemo.Views.CustomDialogWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:prism="http://prismlibrary.com/"Title="自定义弹窗" Height="300" Width="400"><prism:DialogWindow.Style><Style TargetType="prism:DialogWindow"><Setter Property="WindowStyle" Value="None"/><Setter Property="Background" Value="#F5F5F5"/></Style></prism:DialogWindow.Style>
</prism:DialogWindow>
// 注册时指定自定义弹窗窗口
containerRegistry.RegisterDialog<DialogView, DialogViewModel>("CustomDialogWindow");
4.2 异步弹窗交互

通过`TaskCompletionSource`实现异步弹窗结果获取:

private async Task<bool> ShowAsyncDialog()
{var tcs = new TaskCompletionSource<bool>();var parameters = new DialogParameters { { "Message", "异步弹窗测试" } };_dialogService.ShowDialog("DialogView", parameters, result =>{if (result.Result == ButtonResult.OK){tcs.SetResult(result.Parameters.GetValue<bool>("Result"));}else{tcs.SetResult(false);}});return await tcs.Task;
}
4.3 弹窗传参与复杂数据

支持传递复杂对象作为弹窗参数:

// 传递复杂对象
var parameters = new DialogParameters();
parameters.Add("Order", new Order { Id = "123", Amount = 100 });// 弹窗中接收
public void OnDialogOpened(IDialogParameters parameters)
{if (parameters.TryGetValue("Order", out Order order)){// 处理订单数据}
}

http://www.dtcms.com/a/494407.html

相关文章:

  • 阿里云服务器上部署Mosquitto
  • Android 设计模式实战手册(Kotlin 实战版)
  • Android thermal (5)_cooling device(下)
  • 活字格低代码平台实现移动端应用(安卓 /iOS)打包的技术方案与实践指南
  • SpringBoot电子商城系统
  • 解析 Qt Remote Objects:从框架原理到 Repcs 实践,以正点原子 RK3588 UI 系统为例
  • 【底层机制】【Android】Binder架构与原理
  • 揭阳市住房和城乡建设局网站网站类游戏网站开发
  • DeviceNet 转 MODBUS TCP罗克韦尔 ControlLogix PLC 与上位机在汽车零部件涂装生产线漆膜厚度精准控制的通讯配置案例
  • 【STM32项目开源】基于STM32的智能衣柜系统
  • python基于web的汽车班车车票管理系统/火车票预订系统/高铁预定系统 可在线选座
  • ssh终端管理多个k8s集群,快速切换配置
  • 景德镇建站公司全国建筑四库一平台
  • 奥运网站模板wordpress在 分栏
  • toLua[七] Examples 06_LuaCoroutine2分析
  • CAD如何生成等高线
  • Java并发工具类详解:Semaphore、CyclicBarrier与CountDownLatch
  • 御剑问情_附带自动假人版_大型3D仙侠类剧情闯关手游_Linux服务端_通用视频架设教程_GM授权网页后台_运营网页后台_安卓苹果IOS双端
  • 基于信息保留与细粒度特征聚合的无人机目标检测
  • AINode部署全指南:从独立部署到Kubernetes集群部署
  • PYcharm——获取天气
  • Kafka多网卡环境配置
  • TypeScript 与淘宝 API:构建类型安全的商品数据查询前端 / Node.js 服务
  • 网站备案名称要求郴州网站排名优化
  • 百度做一个网站多少钱sns营销
  • List<map<String,Object>下划线转驼峰
  • List.subList() 返回值为什么不能强转成 ArrayList
  • phpcms网站转移网站关键词百度排名在下降
  • mac使用本地jdk启动elasticsearch解决elasticsearch启动时jdk损坏问题
  • 手机在初次联网的底层流程-关于EPC信令附着