对 Prism 框架在 .NET Core 8.0 和 WPF 环境中的详细说明,涵盖其核心功能、常用方法、实用方法、经典案例以及具体实例代码
对 Prism 框架在 .NET Core 8.0 和 WPF 环境中的详细说明,涵盖其核心功能、常用方法、实用方法、经典案例以及具体实例代码。内容基于 Prism 9.0(支持 .NET 8.0),提供深入解析、完整示例和最佳实践,确保满足你对详细性和实用性的需求。文中将结合前述 IEventAggregator 示例,扩展更多场景,并提供更复杂的代码实现。
1. Prism 框架详细说明
1.1 什么是 Prism?
Prism 是一个开源框架,旨在帮助开发者构建松耦合、可维护、可测试的 XAML 应用程序,特别适用于 WPF、.NET MAUI 和 Uno Platform。它基于 MVVM(Model-View-ViewModel)模式,提供以下核心功能:
-
模块化开发:将应用拆分为独立模块,支持动态加载。
-
依赖注入(DI):内置 IoC 容器(如 Unity、DryIoc),管理服务和 ViewModel。
-
导航:支持区域导航(Region Navigation),实现复杂 UI 切换。
-
事件聚合器(EventAggregator):实现模块间松耦合通信。
-
MVVM 支持:提供 BindableBase 和 DelegateCommand,简化属性绑定和命令实现。
1.2 核心组件
-
IModule:定义模块,负责初始化和注册。
-
IRegionManager:管理 UI 区域,注入视图。
-
IEventAggregator:跨模块事件通信。
-
IContainerRegistry/IContainerProvider:依赖注入容器,注册和解析服务。
-
IDialogService:管理模态对话框。
-
INavigationAware:处理导航生命周期。
1.3 优势
-
模块化:支持插件式架构,易于扩展。
-
可测试性:松耦合设计便于单元测试。
-
灵活性:支持多种 IoC 容器和导航模式。
-
社区支持:由 .NET Foundation 维护,文档丰富(https://prismlibrary.com/docs/)。
1.4 适用场景
-
中大型 WPF 应用,如企业级管理系统、仪表盘应用。
-
需要模块化或插件式架构的项目。
-
强调可维护性和可测试性的团队开发。
2. 常用方法
以下是 Prism 的常用方法,按组件分类,附带简要说明。
2.1 IModule
-
OnInitialized(IContainerProvider):模块初始化,注入视图或执行启动逻辑。
-
RegisterTypes(IContainerRegistry):注册模块特定的服务、视图或 ViewModel。
csharp
public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<IMyService, MyService>(); }
2.2 IRegionManager
-
RegisterViewWithRegion(string, Type):将视图注册到指定区域。
csharp
regionManager.RegisterViewWithRegion("ContentRegion", typeof(Views.MyView)); -
RequestNavigate(string, string, NavigationParameters):导航到指定视图。
csharp
regionManager.RequestNavigate("ContentRegion", "MyView", new NavigationParameters { { "id", 123 } });
2.3 IEventAggregator
-
GetEvent<TEvent>():获取事件实例。
csharp
var event = _eventAggregator.GetEvent<MessageSentEvent>(); -
Publish(T):发布事件。
csharp
_eventAggregator.GetEvent<MessageSentEvent>().Publish("Hello"); -
Subscribe(Action<T>, ThreadOption, bool, Predicate<T>):订阅事件。
csharp
_eventAggregator.GetEvent<MessageSentEvent>().Subscribe(msg => Console.WriteLine(msg), ThreadOption.UIThread);
2.4 IDialogService
-
ShowDialog(string, DialogParameters, Action<IDialogResult>):显示模态对话框。
csharp
_dialogService.ShowDialog("MyDialog", new DialogParameters(), result => { /* Handle result */ });
2.5 BindableBase
-
SetProperty<T>(ref T, T, string):设置属性并触发通知。
csharp
private string _title; public string Title { get => _title; set => SetProperty(ref _title, value); }
2.6 DelegateCommand
-
Execute():执行命令逻辑。
-
CanExecute():控制命令是否可用。
csharp
public DelegateCommand SaveCommand { get; } SaveCommand = new DelegateCommand(Save, CanSave);
3. 实用方法
以下是 Prism 的实用方法,解决常见开发问题。
3.1 动态模块加载
使用 DirectoryModuleCatalog 动态加载模块:
csharp
protected override IModuleCatalog CreateModuleCatalog()
{
return new DirectoryModuleCatalog { ModulePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules") };
}
3.2 导航错误处理
捕获导航失败:
csharp
regionManager.RequestNavigate("ContentRegion", "MyView", result =>
{
if (!result.Result)
MessageBox.Show($"Navigation failed: {result.Error.Message}");
});
3.3 事件订阅取消
使用 ISubscriptionToken 管理订阅:
csharp
private readonly ISubscriptionToken _token;
_token = _eventAggregator.GetEvent<MessageSentEvent>().Subscribe(OnMessage);
public void Dispose()
{
_eventAggregator.GetEvent<MessageSentEvent>().Unsubscribe(_token);
}
3.4 区域作用域
创建子区域作用域:
csharp
var scopedRegionManager = regionManager.Regions["SubRegion"].RegionManager;
scopedRegionManager.RequestNavigate("SubRegion", "SubView");
3.5 批量属性更新
优化多属性变更通知:
csharp
public void UpdateProperties(string newTitle, int newCount)
{
bool changed = false;
changed |= SetProperty(ref _title, newTitle, nameof(Title));
changed |= SetProperty(ref _count, newCount, nameof(Count));
if (changed)
RaisePropertyChanged(nameof(IsValid));
}
4. 经典案例
以下是 Prism 在实际项目中的经典应用场景。
4.1 企业级仪表盘
-
需求:多模块仪表盘,支持动态加载图表模块(如销售、库存)。
-
实现:
-
每个图表模块实现 IModule,注册视图到仪表盘区域。
-
使用 IEventAggregator 同步数据更新。
-
支持延迟加载,优化启动时间。
-
4.2 插件式编辑器
-
需求:文本编辑器支持插件(如语法高亮、代码格式化)。
-
实现:
-
使用 DirectoryModuleCatalog 加载插件 DLL。
-
插件通过 IEventAggregator 通信,注入工具栏视图。
-
提供模态对话框配置插件。
-
4.3 导航式业务应用
-
需求:CRM 系统,支持多页面导航(如客户列表、订单详情)。
-
实现:
-
使用 IRegionManager 管理主区域和子区域。
-
实现 INavigationAware 处理导航参数和生命周期。
-
使用 IDialogService 弹出确认对话框。
-
5. 具体实例代码
以下是一个完整的 Prism WPF 示例,展示 模块化、动态加载、导航、事件通信和 对话框 的综合应用,扩展前述 IEventAggregator 示例。
5.1 项目结构
plaintext
MyWpfApp/
├── MyWpfApp.Core/ # 核心类库(.NET 8.0)
│ ├── Events/
│ │ └── MessageSentEvent.cs
│ ├── Services/
│ │ └── IMyService.cs
│ └── ViewModels/
│ └── ViewModelBase.cs
├── MyWpfApp.Wpf/ # WPF 项目(.NET 8.0)
│ ├── App.xaml
│ ├── Views/
│ │ └── MainWindow.xaml
│ ├── ViewModels/
│ │ └── MainWindowViewModel.cs
│ └── Modules/ # 动态模块目录
├── MyWpfApp.Modules.ModuleA/ # 模块 A(.NET 8.0)
│ ├── Views/
│ │ ├── MessageListView.xaml
│ │ ├── MessageSenderView.xaml
│ │ └── SettingsDialogView.xaml
│ ├── ViewModels/
│ │ ├── MessageListViewModel.cs
│ │ ├── MessageSenderViewModel.cs
│ │ └── SettingsDialogViewModel.cs
│ └── ModuleAModule.cs
└── MyWpfApp.sln
5.2 安装 Prism
bash
dotnet add package Prism.Wpf --version 9.0.537
dotnet add package Prism.Unity
5.3 核心类库
-
MessageSentEvent.cs:
csharp
using Prism.Events;
namespace MyWpfApp.Core.Events
{
public class MessageSentEvent : PubSubEvent<string> { }
}
-
IMyService.cs:
csharp
namespace MyWpfApp.Core.Services
{
public interface IMyService
{
string ProcessMessage(string message);
}
public class MyService : IMyService
{
public string ProcessMessage(string message) => $"Processed: {message}";
}
}
-
ViewModelBase.cs:
csharp
using Prism.Mvvm;
namespace MyWpfApp.Core.ViewModels
{
public abstract class ViewModelBase : BindableBase
{
// 公共逻辑
}
}
5.4 主应用程序
-
App.xaml.cs:
csharp
using Prism.Ioc;
using Prism.Modularity;
using Prism.Unity;
using System.IO;
using System.Windows;
namespace MyWpfApp.Wpf
{
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
return Container.Resolve<Views.MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<Core.Services.IMyService, Core.Services.MyService>();
}
protected override IModuleCatalog CreateModuleCatalog()
{
var catalog = new DirectoryModuleCatalog { ModulePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules") };
return catalog;
}
}
}
-
MainWindow.xaml:
xaml
<Window x:Class="MyWpfApp.Wpf.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
Title="Prism Demo" Height="600" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="5">
<Button Content="Load Module A" Command="{Binding LoadModuleCommand}" CommandParameter="ModuleA" Margin="5"/>
<TextBlock Text="{Binding LoadingMessage}" VerticalAlignment="Center"/>
</StackPanel>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<ContentControl prism:RegionManager.RegionName="MessageListRegion"/>
<ContentControl Grid.Column="1" prism:RegionManager.RegionName="MessageSenderRegion"/>
</Grid>
</Grid>
</Window>
-
MainWindowViewModel.cs:
csharp
using Prism.Commands;
using Prism.Modularity;
using Prism.Mvvm;
using System;
using System.Threading.Tasks;
namespace MyWpfApp.Wpf.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private readonly IModuleManager _moduleManager;
private bool _isLoading;
private string _loadingMessage;
public bool IsLoading
{
get => _isLoading;
set => SetProperty(ref _isLoading, value);
}
public string LoadingMessage
{
get => _loadingMessage;
set => SetProperty(ref _loadingMessage, value);
}
public DelegateCommand<string> LoadModuleCommand { get; }
public MainWindowViewModel(IModuleManager moduleManager)
{
_moduleManager = moduleManager;
LoadModuleCommand = new DelegateCommand<string>(AsyncLoadModule);
_moduleManager.LoadModuleCompleted += ModuleManager_LoadModuleCompleted;
}
private async void AsyncLoadModule(string moduleName)
{
IsLoading = true;
LoadingMessage = $"Loading {moduleName}...";
try
{
await Task.Run(() => _moduleManager.LoadModule(moduleName));
}
catch (Exception ex)
{
LoadingMessage = $"Failed to load {moduleName}: {ex.Message}";
}
}
private void ModuleManager_LoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e)
{
IsLoading = false;
LoadingMessage = e.Error == null ? $"{e.ModuleInfo.ModuleName} loaded" : $"Error: {e.Error.Message}";
}
}
}
5.5 Module A
-
ModuleAModule.cs:
csharp
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
namespace MyWpfApp.Modules.ModuleA
{
public class ModuleAModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("MessageListRegion", typeof(Views.MessageListView));
regionManager.RegisterViewWithRegion("MessageSenderRegion", typeof(Views.MessageSenderView));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<Views.MessageListView>();
containerRegistry.Register<Views.MessageSenderView>();
containerRegistry.RegisterDialog<Views.SettingsDialogView, ViewModels.SettingsDialogViewModel>();
containerRegistry.Register<ViewModels.MessageListViewModel>();
containerRegistry.Register<ViewModels.MessageSenderViewModel>();
}
}
}
-
MessageListView.xaml:
xaml
<UserControl x:Class="MyWpfApp.Modules.ModuleA.Views.MessageListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Filter:" VerticalAlignment="Center" Margin="5"/>
<TextBox Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged}" Width="100" Margin="5"/>
</StackPanel>
<ListBox ItemsSource="{Binding Messages}" Grid.Row="1" Margin="5"/>
</Grid>
</UserControl>
-
MessageListViewModel.cs(扩展前述代码):
csharp
using MyWpfApp.Core.Events;
using Prism.Events;
using Prism.Mvvm;
using System;
using System.Collections.ObjectModel;
namespace MyWpfApp.Modules.ModuleA.ViewModels
{
public class MessageListViewModel : BindableBase, IDisposable
{
private readonly IEventAggregator _ea;
private ISubscriptionToken _subscriptionToken;
private ObservableCollection<string> _messages;
private string _filter = "Brian";
public ObservableCollection<string> Messages
{
get => _messages;
set => SetProperty(ref _messages, value);
}
public string Filter
{
get => _filter;
set
{
if (SetProperty(ref _filter, value))
UpdateSubscription();
}
}
public MessageListViewModel(IEventAggregator ea)
{
_ea = ea;
Messages = new ObservableCollection<string>();
UpdateSubscription();
}
private void UpdateSubscription()
{
_ea.GetEvent<MessageSentEvent>().Unsubscribe(_subscriptionToken);
_subscriptionToken = _ea.GetEvent<MessageSentEvent>().Subscribe(
MessageReceived,
ThreadOption.UIThread,
false,
filter => filter.Contains(_filter));
}
private void MessageReceived(string message)
{
Messages.Add(message);
if (Messages.Count > 100)
Messages.RemoveAt(0);
}
public void Dispose()
{
_ea.GetEvent<MessageSentEvent>().Unsubscribe(_subscriptionToken);
}
}
}
-
MessageSenderView.xaml:
xaml
<UserControl x:Class="MyWpfApp.Modules.ModuleA.Views.MessageSenderView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Message:" VerticalAlignment="Center" Margin="5"/>
<TextBox Text="{Binding MessageToSend, UpdateSourceTrigger=PropertyChanged}" Width="200" Margin="5"/>
<Button Content="Send" Command="{Binding SendMessageCommand}" Margin="5"/>
</StackPanel>
<Button Grid.Row="1" Content="Open Settings" Command="{Binding OpenSettingsCommand}" Margin="5"/>
<TextBlock Grid.Row="2" Text="{Binding ProcessedMessage}" Margin="5"/>
</Grid>
</UserControl>
-
MessageSenderViewModel.cs:
csharp
using MyWpfApp.Core.Events;
using MyWpfApp.Core.Services;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Services.Dialogs;
namespace MyWpfApp.Modules.ModuleA.ViewModels
{
public class MessageSenderViewModel : BindableBase
{
private readonly IEventAggregator _ea;
private readonly IMyService _myService;
private readonly IDialogService _dialogService;
private string _messageToSend;
private string _processedMessage;
public string MessageToSend
{
get => _messageToSend;
set => SetProperty(ref _messageToSend, value);
}
public string ProcessedMessage
{
get => _processedMessage;
set => SetProperty(ref _processedMessage, value);
}
public DelegateCommand SendMessageCommand { get; }
public DelegateCommand OpenSettingsCommand { get; }
public MessageSenderViewModel(IEventAggregator ea, IMyService myService, IDialogService dialogService)
{
_ea = ea;
_myService = myService;
_dialogService = dialogService;
SendMessageCommand = new DelegateCommand(SendMessage);
OpenSettingsCommand = new DelegateCommand(OpenSettings);
}
private void SendMessage()
{
if (!string.IsNullOrEmpty(MessageToSend))
{
_ea.GetEvent<MessageSentEvent>().Publish(MessageToSend);
ProcessedMessage = _myService.ProcessMessage(MessageToSend);
MessageToSend = string.Empty;
}
}
private void OpenSettings()
{
var parameters = new DialogParameters { { "CurrentFilter", "Brian" } };
_dialogService.ShowDialog("SettingsDialogView", parameters, result =>
{
if (result.Result == ButtonResult.OK)
{
var newFilter = result.Parameters.GetValue<string>("NewFilter");
ProcessedMessage = $"Settings updated: Filter = {newFilter}";
}
});
}
}
}
-
SettingsDialogView.xaml:
xaml
<Window x:Class="MyWpfApp.Modules.ModuleA.Views.SettingsDialogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Settings" Height="200" Width="300" WindowStartupLocation="CenterOwner">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="Message Filter:" Margin="5"/>
<TextBox Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged}" Margin="5" Grid.Row="1"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="2">
<Button Content="OK" Command="{Binding OkCommand}" Margin="5"/>
<Button Content="Cancel" Command="{Binding CancelCommand}" Margin="5"/>
</StackPanel>
</Grid>
</Window>
-
SettingsDialogViewModel.cs:
csharp
using Prism.Commands;
using Prism.Mvvm;
using Prism.Services.Dialogs;
namespace MyWpfApp.Modules.ModuleA.ViewModels
{
public class SettingsDialogViewModel : BindableBase, IDialogAware
{
private string _filter;
public string Filter
{
get => _filter;
set => SetProperty(ref _filter, value);
}
public DelegateCommand OkCommand { get; }
public DelegateCommand CancelCommand { get; }
public event Action<IDialogResult> RequestClose;
public SettingsDialogViewModel()
{
OkCommand = new DelegateCommand(OnOk);
CancelCommand = new DelegateCommand(OnCancel);
}
private void OnOk()
{
var result = new DialogResult(ButtonResult.OK, new DialogParameters { { "NewFilter", Filter } });
RequestClose?.Invoke(result);
}
private void OnCancel()
{
RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel));
}
public bool CanCloseDialog() => true;
public void OnDialogClosed() { }
public void OnDialogOpened(IDialogParameters parameters)
{
Filter = parameters.GetValue<string>("CurrentFilter");
}
}
}
5.6 运行效果
-
启动应用,点击“Load Module A”加载模块。
-
左侧显示 MessageListView,右侧显示 MessageSenderView。
-
在 MessageSenderView 输入消息(如 “Hello from Brian”),点击“Send”,消息通过 IEventAggregator 发布。
-
MessageListView 仅显示包含过滤器(如 “Brian”)的消息。
-
点击“Open Settings”弹出对话框,修改过滤器,更新 MessageListView 的订阅。
-
MyService 处理消息并显示在 MessageSenderView。
6. 更详细的示例:嵌套导航和动态模块管理
以下是一个更复杂的示例,展示 嵌kit区域导航 和 动态模块管理,进一步扩展功能。
6.1 项目结构扩展
plaintext
MyWpfApp.Modules.ModuleB/
├── Views/
│ ├── DashboardView.xaml
│ ├── ChartView.xaml
├── ViewModels/
│ ├── DashboardViewModel.cs
│ ├── ChartViewModel.cs
└── ModuleBModule.cs
6.2 Module B 实现
-
ModuleBModule.cs:
csharp
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
namespace MyWpfApp.Modules.ModuleB
{
public class ModuleBModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("MessageSenderRegion", typeof(Views.DashboardView));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<Views.DashboardView>();
containerRegistry.Register<Views.ChartView>();
containerRegistry.Register<ViewModels.DashboardViewModel>();
containerRegistry.Register<ViewModels.ChartViewModel>();
}
}
}
-
DashboardView.xaml:
xaml
<UserControl x:Class="MyWpfApp.Modules.ModuleB.Views.DashboardView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Content="Show Chart" Command="{Binding ShowChartCommand}" Margin="5"/>
<ContentControl Grid.Row="1" prism:RegionManager.RegionName="ChartRegion"/>
</Grid>
</UserControl>
-
DashboardViewModel.cs:
csharp
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
namespace MyWpfApp.Modules.ModuleB.ViewModels
{
public class DashboardViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
public DelegateCommand ShowChartCommand { get; }
public DashboardViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
ShowChartCommand = new DelegateCommand(ShowChart);
}
private void ShowChart()
{
var scopedRegionManager = _regionManager.CreateRegionManager();
var region = _regionManager.Regions["ChartRegion"];
region.RegionManager = scopedRegionManager;
scopedRegionManager.RequestNavigate("ChartRegion", "ChartView");
}
}
}
-
ChartView.xaml:
xaml
<UserControl x:Class="MyWpfApp.Modules.ModuleB.Views.ChartView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock Text="{Binding ChartData}" FontSize="20" Background="LightBlue" Margin="10"/>
</UserControl>
-
ChartViewModel.cs:
csharp
using MyWpfApp.Core.Events;
using Prism.Events;
using Prism.Mvvm;
namespace MyWpfApp.Modules.ModuleB.ViewModels
{
public class ChartViewModel : BindableBase
{
private string _chartData = "Chart Data";
public string ChartData
{
get => _chartData;
set => SetProperty(ref _chartData, value);
}
public ChartViewModel(IEventAggregator ea)
{
ea.GetEvent<MessageSentEvent>().Subscribe(UpdateChart, ThreadOption.UIThread);
}
private void UpdateChart(string message)
{
ChartData = $"Chart updated with: {message}";
}
}
}
6.3 动态模块管理
扩展 MainWindowViewModel 支持模块卸载:
csharp
public DelegateCommand<string> UnloadModuleCommand { get; }
public MainWindowViewModel(IModuleManager moduleManager)
{
_moduleManager = moduleManager;
LoadModuleCommand = new DelegateCommand<string>(AsyncLoadModule);
UnloadModuleCommand = new DelegateCommand<string>(UnloadModule);
_moduleManager.LoadModuleCompleted += ModuleManager_LoadModuleCompleted;
}
private void UnloadModule(string moduleName)
{
// 假设支持卸载(需自定义 IModuleManager 扩展)
LoadingMessage = $"Unloading {moduleName} not supported in default Prism.";
}
6.4 运行效果
-
加载 Module A 显示消息列表和发送界面。
-
加载 Module B 显示仪表盘,点击“Show Chart”在子区域显示图表。
-
Module A 发送消息,Module B 的图表通过 IEventAggregator 更新。
-
动态调整 Module A 的消息过滤器,影响消息显示。
7. 性能优化和注意事项
7.1 性能优化
-
延迟加载:如前述,使用 InitializationMode.OnDemand。
-
异步操作:模块初始化和导航使用 async/await。
-
视图缓存:实现 IRegionMemberLifetime 复用视图:
csharp
public bool KeepAlive => true; -
事件清理:确保 IDisposable 取消事件订阅。
7.2 注意事项
-
线程安全:始终使用 ThreadOption.UIThread 或 Dispatcher 操作 UI。
-
模块依赖:避免模块间直接引用,使用 IEventAggregator 或共享服务。
-
XAML 性能:减少复杂绑定,使用 OneWay 模式。
-
测试:为 ViewModel 和服务编写单元测试:
csharp
[Fact] public void MessageListViewModel_AddsFilteredMessage() { var ea = new EventAggregator(); var vm = new MessageListViewModel(ea); ea.GetEvent<MessageSentEvent>().Publish("Hello from Brian"); Assert.Single(vm.Messages); Assert.Equal("Hello from Brian", vm.Messages[0]); }
8. 参考资料
-
Prism 官方文档:https://prismlibrary.com/docs/
-
Prism Samples(WPF):https://github.com/PrismLibrary/Prism-Samples-Wpf
-
Brian Lagunas 教程:
-
GitHub Issues:https://github.com/PrismLibrary/Prism/issues
9. 总结
-
Prism 核心:提供模块化、导航、事件通信和 MVVM 支持,适合复杂 WPF 应用。
-
常用方法:RegisterViewWithRegion、RequestNavigate、GetEvent 等简化开发。
-
实用方法:动态加载、错误处理、区域作用域增强灵活性。
-
经典案例:仪表盘、插件编辑器、导航应用展示 Prism 能力。
-
实例代码:提供完整示例,覆盖模块化、导航、事件和对话框。
-
优化:延迟加载、异步操作和视图缓存确保高性能。
如果需要更具体功能(如动态主题、复杂数据绑定)或进一步代码调试,请告诉我!
更多推荐


所有评论(0)