目录
2. DelegateCommand/DelegateCommand :行为的封装
3. 消息委托的引用方式(keepSubscriberReferenceAlive)
Prism框架中的区域化管理(Region Management)
Prism中的基本对象
数据与行为对象
1. BindableBase:数据绑定的基础
BindableBase
是 Prism 中实现 数据绑定通知 的核心基类,继承自 INotifyPropertyChanged
接口。它简化了属性变更通知的触发逻辑,确保 UI 能够自动响应数据变化。
作用与特性
- 自动触发通知:通过
SetProperty
方法设置属性值,自动触发PropertyChanged
事件。 - 减少样板代码:避免手动编写
if (value != field) { ... }
和事件触发逻辑。 - 支持派生类:ViewModel 通常继承
BindableBase
,直接使用其功能。
关键方法
SetProperty(ref T field, T value)
:基础属性设置。SetProperty(ref T field, T value, Action onChanged)
:设置属性并执行回调。RaisePropertyChanged(string propertyName)
:手动触发指定属性的通知。
使用示例
- public class UserViewModel : BindableBase
- {
- private string _name;
- public string Name
- {
- get => _name;
- set => SetProperty(ref _name, value); // 自动触发PropertyChanged事件
- }
-
- private int _age;
- public int Age
- {
- get => _age;
- set => SetProperty(ref _age, value, () =>
- {
- // 可选:属性变更后的回调逻辑(如验证)
- });
- }
- }
2. DelegateCommand/DelegateCommand:行为的封装
DelegateCommand
是 Prism 对 ICommand
接口的实现,用于将 UI 操作(如按钮点击) 绑定到 ViewModel 中的方法,支持条件执行(CanExecute
)。
作用与特性
- 解耦 UI 与逻辑:将点击事件转化为命令,直接在 ViewModel 中处理。
- 支持条件执行:通过
CanExecute
控制命令是否可用(如按钮禁用状态)。 - 泛型与非泛型:
DelegateCommand
无参数,DelegateCommand
支持参数传递。
关键方法
Execute()
:命令执行时调用的方法。CanExecute()
:返回bool
,决定命令是否可用。RaiseCanExecuteChanged()
:手动触发CanExecute
的重新检查。
使用示例
无参数命令
- public class UserViewModel : BindableBase
- {
- // 定义命令
- public DelegateCommand SaveCommand { get; }
-
- public UserViewModel()
- {
- // 绑定执行方法与条件检查
- SaveCommand = new DelegateCommand(ExecuteSave, CanSave);
- }
-
- private void ExecuteSave()
- {
- // 保存逻辑
- }
-
- private bool CanSave()
- {
- // 检查保存条件(如数据有效性)
- return !string.IsNullOrEmpty(Name);
- }
-
- // 当Name属性变化时,手动触发CanExecute检查
- public string Name
- {
- get => _name;
- set
- {
- SetProperty(ref _name, value);
- SaveCommand.RaiseCanExecuteChanged(); // 通知命令重新检查条件
- }
- }
- }
带参数的命令
- public DelegateCommand<int> DeleteCommand { get; }
-
- public UserViewModel()
- {
- DeleteCommand = new DelegateCommand<int>(ExecuteDelete, CanDelete);
- }
-
- private void ExecuteDelete(int userId)
- {
- // 删除指定用户
- }
-
- private bool CanDelete(int userId)
- {
- return userId > 0; // 仅当userId有效时允许执行
- }
在 XAML 中绑定命令
- <Button Command="{Binding SaveCommand}" Content="Save" />
- <Button Command="{Binding DeleteCommand}" CommandParameter="{Binding SelectedUser.Id}" Content="Delete" />
Prism框架中的IoC(控制反转)容器
在Prism框架中,IoC容器是实现依赖注入(DI)的核心机制,用于管理组件生命周期、解耦服务依赖并支持模块化开发。Prism默认支持多种容器(如 Unity、DryIoc)。
1. 核心接口与配置
1.1 容器配置入口
Prism应用的入口类(继承自PrismApplication
)负责初始化容器:
- public partial class App : PrismApplication
- {
- protected override void RegisterTypes(IContainerRegistry containerRegistry)
- {
- // 注册全局服务
- containerRegistry.RegisterSingleton
(); - containerRegistry.Register
(); - }
-
- protected override Window CreateShell()
- {
- return Container.Resolve
(); - }
- }
1.2 关键接口
IContainerRegistry
:用于注册服务(接口与实现的映射)。IContainerProvider
:用于解析(获取)已注册的服务实例。
2. 服务注册方式
2.1 基础注册
接口绑定实现类:
containerRegistry.Register();
直接注册具体类(无需接口):
containerRegistry.Register();
2.2 生命周期控制
单例(Singleton):全局唯一实例。
containerRegistry.RegisterSingleton();
瞬态(Transient):每次解析创建新实例。
containerRegistry.Register();
实例注册:直接注入已有实例。
- var logger = new FileLogger();
- containerRegistry.RegisterInstance
(logger);
3. 依赖注入方式
3.1 构造函数注入(推荐)
ViewModel或服务通过构造函数声明依赖,容器自动注入:
- public class UserViewModel
- {
- private readonly IDataService _dataService;
-
- public UserViewModel(IDataService dataService)
- {
- _dataService = dataService; // 由容器自动注入
- }
- }
3.2 属性注入(需谨慎)
通过 [Dependency]
特性标记需注入的属性:
- public class OrderService
- {
- [Dependency]
- public ILogger Logger { get; set; }
- }
4. 模块化中的IoC
每个Prism模块(实现 IModule
接口)可独立注册服务:
- public class DataModule : IModule
- {
- public void RegisterTypes(IContainerRegistry containerRegistry)
- {
- containerRegistry.Register
(); - }
-
- public void OnInitialized(IContainerProvider containerProvider)
- {
- // 模块初始化逻辑(如预加载数据)
- }
- }
5. 解析服务
通过 IContainerProvider
或构造函数隐式解析服务:
- // 在ViewModel中解析服务
- public class MainViewModel
- {
- public MainViewModel(IContainerProvider containerProvider)
- {
- var service = containerProvider.Resolve
(); - }
- }
6. 高级功能
6.1 命名注册
同一接口多个实现时,使用名称区分:
- containerRegistry.Register
("Email"); - containerRegistry.Register
("SMS"); -
- // 解析指定名称的实现
- var emailService = container.Resolve
("Email");
6.2 延迟加载与工厂模式
通过 Func
或 IocContainer.CreateScope
实现复杂依赖管理:
containerRegistry.Register(() => new ServiceFactory());
Prism框架中的消息对象(事件总线)
在Prism框架中,事件总线(Event Aggregator) 是实现松耦合跨组件通信的核心机制。它通过发布-订阅模式(Pub-Sub)让不同模块、视图或服务之间无需直接引用即可传递消息,尤其适用于模块化架构和MVVM模式。
1. 核心组件
IEventAggregator
:
事件聚合器的入口接口,负责创建和管理事件对象。
通过依赖注入获取实例:
- public class MyViewModel
- {
- private readonly IEventAggregator _eventAggregator;
-
- public MyViewModel(IEventAggregator eventAggregator)
- {
- _eventAggregator = eventAggregator;
- }
- }
PubSubEvent
:
所有自定义事件的基类,泛型T
定义事件传递的数据类型。
开发者需继承此类创建特定事件:
public class UserLoggedInEvent : PubSubEvent<UserInfo> { }
2. 使用流程
2.1 定义事件类
创建继承自 PubSubEvent
的事件类,定义事件的数据类型:
- // 无参数事件
- public class AppShutdownEvent : PubSubEvent { }
-
- // 带参数事件
- public class OrderSubmittedEvent : PubSubEvent<Order> { }
2.2 发布事件
通过 GetEvent
获取事件实例并发布数据:
- // 发布无参数事件
- _eventAggregator.GetEvent
().Publish(); -
- // 发布带参数事件
- var order = new Order { Id = 123, Amount = 100.0 };
- _eventAggregator.GetEvent
().Publish(order);
2.3 订阅事件
- // 订阅事件(自动强引用,需手动取消订阅)
- _eventAggregator.GetEvent
() - .Subscribe(OnOrderSubmitted);
-
- // 处理事件的回调方法
- private void OnOrderSubmitted(Order order)
- {
- // 处理订单提交逻辑
- MessageBox.Show($"订单 {order.Id} 已提交!");
- }
3. 高级配置
3.1 订阅选项
通过 Subscribe
方法的参数配置订阅行为:
- _eventAggregator.GetEvent
() - .Subscribe(
- onOrderSubmitted, // 回调方法
- ThreadOption.UIThread, // 在UI线程执行
- keepSubscriberReferenceAlive: false, // 弱引用
- filter: order => order.UserId == _currentUserId // 仅处理当前用户的订单
- );
各参数的应用场景总结
参数 | 典型场景 |
回调方法 | 执行具体的业务逻辑(如更新数据库、刷新UI)。 |
| 过滤无关事件(如只处理特定用户或状态的数据)。 |
| 控制订阅者生命周期(View/ViewModel用弱引用,服务层可强引用)。 |
| 解决跨线程问题(UI操作必须在UI线程,耗时操作在后台线程)。 |
详细使用教程
1. 主要委托方法(回调逻辑)
- 作用:定义事件触发时执行的核心逻辑。
- 语法:通过
Action
或带参数的委托实现。 - 示例:
- _eventAggregator.GetEvent
() - .Subscribe(OnOrderSubmitted); // OnOrderSubmitted为回调方法
-
- private void OnOrderSubmitted(Order order)
- {
- // 处理订单提交逻辑
- _logger.Log($"订单 {order.Id} 已处理");
- }
2. 消息过滤条件(filter
)
- 作用:根据条件过滤事件,仅当数据满足条件时触发回调。
- 类型:
Predicate
(返回bool
的表达式)。 - 示例:
- .Subscribe(OnHighValueOrder,
- filter: order => order.Amount > 1000 // 仅处理金额超过1000的订单
- );
- 场景:
-
- 仅处理特定类型的数据(如高优先级任务)。
- 避免不必要的事件响应(如仅关注当前用户的订单)。
3. 消息委托的引用方式(keepSubscriberReferenceAlive
)
- 作用:控制订阅者的生命周期引用方式,防止内存泄漏。
- 可选值:
-
true
:强引用,订阅者不会被垃圾回收,需手动取消订阅。false
(默认):弱引用,订阅者销毁后自动取消订阅。
- 示例:
- // 使用弱引用(推荐)
- .Subscribe(OnOrderSubmitted,
- keepSubscriberReferenceAlive: false
- );
-
- // 使用强引用(需手动管理)
- .Subscribe(OnOrderSubmitted,
- keepSubscriberReferenceAlive: true
- );
- 最佳实践:
-
- ViewModel/View 订阅事件时,默认使用弱引用(避免因未取消订阅导致内存泄漏)。
- 全局服务 或长期存在的对象可使用强引用,但需在不再需要时调用
Unsubscribe
。
4. 多线程状态控制(ThreadOption
)
- 作用:指定回调方法在哪个线程执行,解决跨线程访问UI的问题。
- 可选值:
-
PublisherThread
:在发布事件的线程执行(默认)。UIThread
:在UI线程执行(安全更新界面)。BackgroundThread
:在线程池后台线程执行(避免阻塞UI)。
- 示例:
- // 在UI线程更新界面
- .Subscribe(UpdateUI,
- ThreadOption.UIThread
- );
-
- // 在后台线程处理耗时操作
- .Subscribe(ProcessData,
- ThreadOption.BackgroundThread
- );
- 线程安全场景:
-
- UI操作:必须使用
UIThread
,否则会抛出跨线程异常。 - 数据计算/IO操作:使用
BackgroundThread
避免阻塞主线程。 - 同步上下文:若发布者本身在UI线程,
PublisherThread
等同于UIThread
。
- UI操作:必须使用
3.2 取消订阅
- 手动取消:
保存订阅令牌(SubscriptionToken
),调用Unsubscribe
方法。
- private SubscriptionToken _token;
-
- _token = _eventAggregator.GetEvent
() - .Subscribe(OnOrderSubmitted);
-
- // 取消订阅
- _eventAggregator.GetEvent
().Unsubscribe(_token);
- 自动取消:
使用弱引用(keepSubscriberReferenceAlive: false
),订阅者销毁时自动取消订阅。
4. 实际应用场景
4.1 跨模块通信
- 场景:订单模块提交订单后,通知购物车模块清空购物车。
- 实现:
- // 订单模块发布事件
- _eventAggregator.GetEvent
().Publish(order); -
- // 购物车模块订阅事件
- _eventAggregator.GetEvent
() - .Subscribe(_ => ClearCart());
4.2 全局状态通知
- 场景:用户登录后,通知所有模块更新界面。
- 实现:
- // 登录成功后发布事件
- _eventAggregator.GetEvent
().Publish(userInfo); -
- // 各模块订阅事件
- _eventAggregator.GetEvent
() - .Subscribe(UpdateUI);
4.3 弹窗交互
- 场景:在ViewModel中触发弹窗,无需直接操作View。
- 实现:
- // 定义弹窗事件
- public class ShowDialogEvent : PubSubEvent<DialogParameters> { }
-
- // 发布弹窗请求
- var parameters = new DialogParameters { { "message", "保存成功!" } };
- _eventAggregator.GetEvent
().Publish(parameters); -
- // 弹窗服务订阅事件并显示弹窗
- _eventAggregator.GetEvent
() - .Subscribe(ShowDialog, ThreadOption.UIThread);
-
- private void ShowDialog(DialogParameters parameters)
- {
- _dialogService.ShowDialog("MessageDialog", parameters);
- }
Prism框架中的弹窗对象
1. 核心组件
1.1 IDialogService
- 作用:管理弹窗的显示、关闭及结果回调。
- 关键方法:
- // 显示弹窗
- void ShowDialog(string name, IDialogParameters parameters, Action
callback ); -
- // 显示模态弹窗(阻塞式)
- void Show(string name, IDialogParameters parameters, Action
callback );
1.2 IDialogAware
- 作用:弹窗ViewModel必须实现的接口,定义弹窗的生命周期方法。
- 核心成员:
- bool CanCloseDialog(); // 控制弹窗是否允许关闭
- void OnDialogOpened(IDialogParameters parameters); // 弹窗打开时接收参数
- string Title { get; } // 弹窗标题
2. 创建弹窗的完整流程
2.1 定义弹窗视图(View)
- XAML示例(
WarningDialog.xaml
):
- xmlns:prism="http://prismlibrary.com/"
- prism:ViewModelLocator.AutoWireViewModel="True">
-
-
"{Binding Message}" Margin="10"/> -
-
-
2.2 实现弹窗ViewModel
- 继承
IDialogAware
并处理逻辑:
- public class WarningDialogViewModel : BindableBase, IDialogAware
- {
- // 实现IDialogAware
- public string Title => "警告";// 弹出窗口的标题
- public event Action
RequestClose;// 执行关闭返回 -
- private string _message;
- public string Message
- {
- get => _message;
- set => SetProperty(ref _message, value);
- }
-
- // 命令定义
- public DelegateCommand ConfirmCommand { get; }
- public DelegateCommand CancelCommand { get; }
-
- public WarningDialogViewModel()
- {
- ConfirmCommand = new DelegateCommand(() =>RequestClose?.Invoke(new DialogResult(ButtonResult.OK)));
- CancelCommand = new DelegateCommand(() =>RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel)));
- }
-
- // 当弹出窗口关闭时执行的逻辑
- public void OnDialogClosed()
- {
-
- }
-
- // 当弹出窗口打开的时候执行的逻辑
- public void OnDialogOpened(IDialogParameters parameters)
- {
- // 接收参数
- Message = parameters.GetValue<string>("message");
- }
-
- public bool CanCloseDialog() => true; // 允许直接关闭
- }
2.3 注册弹窗
- 在App或模块中注册:
- protected override void RegisterTypes(IContainerRegistry containerRegistry)
- {
- containerRegistry.RegisterDialog
("WarningDialog"); - }
3. 触发弹窗显示
3.1 在ViewModel中调用弹窗
- public class MainViewModel
- {
- private readonly IDialogService _dialogService;
-
- public MainViewModel(IDialogService dialogService)
- {
- _dialogService = dialogService;
- }
-
- public DelegateCommand ShowDialogCommand => new DelegateCommand(() =>
- {
- var parameters = new DialogParameters
- {
- { "message", "确定要删除此文件吗?" }
- };
-
- _dialogService.ShowDialog("WarningDialog", parameters, result =>
- {
- if (result.Result == ButtonResult.OK)
- {
- // 用户点击确认后的逻辑
- DeleteFile();
- }
- });
- });
- }
3.2 直接通过View触发(不推荐,破坏MVVM)
4. 高级功能
4.1 自定义弹窗样式
- 覆盖默认样式:
在App.xaml
中定义全局弹窗样式:
4.2 异步弹窗交互
- 使用
Task
封装弹窗结果:
- public async Task<bool> ShowConfirmationAsync(string message)
- {
- var tcs = new TaskCompletionSource<bool>();
- var parameters = new DialogParameters { { "message", message } };
-
- _dialogService.ShowDialog("ConfirmationDialog", parameters, result =>
- {
- tcs.SetResult(result.Result == ButtonResult.OK);
- });
-
- return await tcs.Task;
- }
4.3 弹窗传参与复杂数据
- 传递对象参数:
- var order = new Order { Id = 123, Amount = 100.0 };
- parameters.Add("order", order);
- 接收并处理对象:
- public void OnDialogOpened(IDialogParameters parameters)
- {
- var order = parameters.GetValue
("order"); - // 使用order数据...
- }
Prism框架中的区域化管理(Region Management)
Prism的 区域化管理(Region Management) 是其核心功能之一,用于实现动态UI组合和模块化布局。通过将界面划分为逻辑区域(Regions),各模块可独立向这些区域注入视图,无需直接操作主窗口控件,从而实现高度解耦和灵活扩展。
1. 核心概念
- 区域(Region):UI中的占位符容器(如
ContentControl
、TabControl
),用于动态承载视图。 - 区域管理器(
IRegionManager
):负责管理区域的生命周期、视图注入和导航。 - 区域适配器(
RegionAdapter
):将不同控件(如ItemsControl
、TabControl
)适配为可管理的区域。
2. 区域的定义与注册
2.1 在XAML中标记区域
使用 prism:RegionManager.RegionName
附加属性定义区域:
-
-
-
"HeaderRegion" /> -
-
-
"MainRegion" /> -
-
-
"SidebarRegion" /> -
2.2 通过代码动态注册区域
在ViewModel或模块中动态创建区域:
- var regionManager = Container.Resolve
(); - regionManager.Regions.Add("DynamicRegion", new Region());
3. 视图注入与导航
3.1 向区域注入视图
- 方法1:直接注册视图
在模块初始化时注册视图到指定区域:
- public class OrdersModule : IModule
- {
- public void OnInitialized(IContainerProvider containerProvider)
- {
- var regionManager = containerProvider.Resolve
(); - regionManager.RegisterViewWithRegion("MainRegion", typeof(OrderListView));
- }
- }
- 方法2:通过导航请求加载视图
动态导航到指定视图(支持参数传递):
- var parameters = new NavigationParameters();
- parameters.Add("orderId", 123);
-
- _regionManager.RequestNavigate("MainRegion", "OrderDetailView", parameters);
3.2 视图导航生命周期
在ViewModel中实现 INavigationAware
接口处理导航事件:
- public class OrderDetailViewModel : INavigationAware
- {
- public void OnNavigatedTo(NavigationContext navigationContext)
- {
- // 获取参数
- var orderId = navigationContext.Parameters.GetValue<int>("orderId");
- LoadOrder(orderId);
- }
-
- public bool IsNavigationTarget(NavigationContext navigationContext) => true;
-
- public void OnNavigatedFrom(NavigationContext navigationContext)
- {
- // 清理资源
- }
- }
4. 区域适配器(支持复杂控件)
Prism内置了多种区域适配器,扩展支持常见控件:
ContentControlRegionAdapter
:适配 ContentControl
(单视图替换)。ItemsControlRegionAdapter
:适配 ItemsControl
(多视图叠加)。SelectorRegionAdapter
:适配 TabControl
、ListBox
等(支持选中项切换)。
自定义区域适配器
若需支持特殊控件(如第三方图表容器),可继承 RegionAdapterBase
:
- public class ChartRegionAdapter : RegionAdapterBase<ChartControl>
- {
- protected override void Adapt(IRegion region, ChartControl regionTarget)
- {
- region.Views.CollectionChanged += (sender, args) =>
- {
- foreach (var view in region.Views)
- {
- regionTarget.AddSeries(view as ChartSeries);
- }
- };
- }
- }
-
- // 注册适配器
- protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
- {
- var mappings = base.ConfigureRegionAdapterMappings();
- mappings.RegisterMapping(typeof(ChartControl), Container.Resolve
()); - return mappings;
- }
5. 区域上下文(共享数据)
- 设置区域上下文:
向区域传递共享数据,供子视图访问:
_regionManager.Regions["MainRegion"].Context = new SharedData { UserId = 456 };
- 在视图中获取上下文:
通过 IRegionMemberLifetime
或依赖注入获取:
- public class OrderListView
- {
- public OrderListView(IRegionManager regionManager)
- {
- var context = regionManager.Regions["MainRegion"].Context;
- }
- }
Prism框架中的模块化设计
1. 模块的核心组成
每个模块需实现 IModule
接口,包含两个关键方法:
- public interface IModule
- {
- void RegisterTypes(IContainerRegistry containerRegistry); // 注册依赖
- void OnInitialized(IContainerProvider containerProvider); // 模块初始化逻辑
- }
2. 模块的创建与配置
2.1 定义模块
- public class OrdersModule : IModule
- {
- // 注册模块专属服务
- public void RegisterTypes(IContainerRegistry containerRegistry)
- {
- containerRegistry.Register
(); - containerRegistry.RegisterForNavigation
("OrderList"); // 注册视图 - }
-
- // 初始化模块(如预加载数据、订阅全局事件)
- public void OnInitialized(IContainerProvider containerProvider)
- {
- var regionManager = containerProvider.Resolve
(); - regionManager.RegisterViewWithRegion("MainRegion", typeof(OrderListView));
- }
- }
2.2 模块目录配置
通过 ModuleCatalog
定义模块的加载顺序和依赖关系,支持多种配置方式:
- 代码配置(显式声明):
- protected override void ConfigureModuleCatalog(IModuleCatalog catalog)
- {
- catalog.AddModule
() - .AddModule
(dependsOn: nameof(OrdersModule)) // 依赖OrdersModule - .AddModule
(InitializationMode.OnDemand); // 按需加载 - }
- 文件配置(XML/JSON):
-
"OrdersModule" Type="MyApp.Orders.OrdersModule, MyApp.Orders" /> -
"CustomersModule" Type="MyApp.Customers.CustomersModule" StartupLoaded="false" />
- protected override IModuleCatalog CreateModuleCatalog()
- {
- return new ConfigurationModuleCatalog(new Uri("pack://application:,,,/modules.xml"));
- }
- 目录扫描(动态发现):
- protected override IModuleCatalog CreateModuleCatalog()
- {
- return new DirectoryModuleCatalog { ModulePath = @".\Modules" };
- }
3. 模块加载策略
- 按需加载(On-Demand):
延迟加载模块以减少启动时间,通过代码触发加载:
- var moduleManager = containerProvider.Resolve
(); - moduleManager.LoadModule("ReportsModule");
- 按顺序加载:
通过 dependsOn
确保依赖模块优先初始化。 - 条件加载:
根据运行时环境(如用户权限)动态决定是否加载模块:
- if (user.IsAdmin)
- moduleManager.LoadModule("AdminToolsModule");
4. 模块间的通信与解耦
- 依赖注入:
模块通过接口共享服务,避免直接依赖实现类。
- // 模块A注册服务
- public void RegisterTypes(IContainerRegistry registry)
- {
- registry.Register
(); - }
-
- // 模块B使用服务
- public class ReportViewModel
- {
- public ReportViewModel(IDataExporter exporter) { ... }
- }
- 事件聚合器:
跨模块事件通知,实现松耦合交互。
- // 模块A发布事件
- _eventAggregator.GetEvent
().Publish(data); -
- // 模块B订阅事件
- _eventAggregator.GetEvent
().Subscribe(RefreshData);
评论记录:
回复评论: