Prism简述
- 模块(Module):独立的功能单元,可动态加载。
- 依赖注入(Dependency Injection,DI):通过 IoC 容器(如 Unity、Autofac)管理模块之间的依赖关系。(一个类型是具体的(非抽象的)并且有一个公共构造函数,容器在需要的时候就会自动创建它的实例,即使你没有显式地在容器中注册该类型)
- 区域管理(Region Management):使用
IRegionManager
进行动态 UI 组件加载。 - 事件聚合(Event Aggregator):使用
IEventAggregator
进行模块间通信。
Prism 项目创建(MVVM)
1. 安装Prism
Install-Package Prism.Unity
关于Prism.Core与Prism.Unity的关系
- Prism.Core 是 Prism 的基础库,提供核心功能(事件聚合、命令、MVVM 基础功能等),适用于所有平台(如 WPF、Xamarin)。
- Prism.Unity 依赖于 Prism.Core,并为 Prism 提供 Unity 依赖注入支持,模块化开发、区域管理,适用于 WPF 应用。
2. 创建启动类
2.1 修改App.xaml
① 添加命名空间xmlns:prism="http://prismlibrary.com/"
② 将标签名修改为prism:PrismApplication
③ 删除StartUri
示例代码
<prism:PrismApplication x:Class="YourApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourApp"
xmlns:prism="http://prismlibrary.com/">
<Application.Resources>
</Application.Resources>
</prism:PrismApplication>
2.2 修改App.xaml.cs
① 实现PrismApplication类
② 重写CreateShell()与ConfigureModuleCatalog(IModuleCatalog moduleCatalog
③ (可选)重写RegisterTypes(IContainerRegistry containerRegistry)
注:App.xaml.cs中所做的设置均为全局设置
注:App.xaml.cs实例由WPF框架创建,无法通过构造函数依赖注入。若想获取IRegionManager可通过 var regionManager = Container.Resolve<IRegionManager>() 获取,IEventAggregator同理
示例代码
public partial class App : PrismApplication
{
/**
* 此处设置均为全局设置
*/
/**
* 解析并返回主窗口
*/
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
/**
* 注册服务: 依赖注入或导航
* 例如: containerRegistry.Register<IMessageService, MessageService>();
* 例如: containerRegistry.RegisterSingleton<IMessageService, MessageService>();
* 例如: containerRegistry.RegisterForNavigation<ViewA>();
*
* IRegionManager与IEventAggregator已由Prism注册
*/
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
}
/**
* 模块注册
* (
* 按需加载
* moduleCatalog.AddModule<ModuleA>(InitializationMode.OnDemand);
* (在其他地方)
* private readonly IModuleManager _moduleManager;
* public MyClass(IModuleManager moduleManager)
* {
* _moduleManager = moduleManager;
* }
* ......
* _moduleManager.LoadModule("ModuleA");
* )
*/
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
moduleCatalog.AddModule<ModuleA>();
moduleCatalog.AddModule<ModuleB>();
}
}
3. 创建主窗口
① 添加命名空间 xmlns:prism="http://prismlibrary.com/"
② 添加区域(Region)以动态加载View(例如:<ContentControl prism:RegionManager.RegionName="MainRegion"/>)
注:主窗口至少需要一个区域
示例代码
<Window x:Class="YourApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:YourApp"
xmlns:prism="http://prismlibrary.com/"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ContentControl prism:RegionManager.RegionName="MainRegion"/>
<ContentControl prism:RegionManager.RegionName="MessageRegion" Grid.Column="1"/>
</Grid>
</Window>
4. 创建模块
① 实现IModule接口
② 实现OnInitialized(IContainerProvider containerProvider)与RegisterTypes(IContainerRegistry containerRegistry)
注:模块中所做的设置仅在模块被加载时才生效
示例代码
public class ModuleA : IModule
{
/**
* 模块中的一切设置均局限于本模块内 仅在模块被加载时生效
*/
private readonly IRegionManager _regionManager;
public ModuleA(IRegionManager regionManager)
{
_regionManager = regionManager;
}
/**
* 模块初始化逻辑
*/
public void OnInitialized(IContainerProvider containerProvider)
{
// 将 ViewA 区域注入至 MainRegion(或者说将 MainRegion 的初始视图设置为 ViewA)
_regionManager.RegisterViewWithRegion("MainRegion", typeof(ViewA));
}
/**
* 注册服务: 依赖注入或导航
*/
public void RegisterTypes(IContainerRegistry containerRegistry)
{
// 注册导航服务
containerRegistry.RegisterForNavigation<ViewA>();
containerRegistry.RegisterForNavigation<ViewB>();
}
}
5. 创建View与ViewModel
说明:
① View与ViewModel的自动绑定规则:
View位于Views文件夹下,ViewModel位于ViewModels文件夹下
Views文件夹与ViewModels文件夹位于同一命名空间
ViewModel的命名为xxxViewModel(xxx为View的命名)
② BindableBase类:类继承BindableBase类后,通过SetProperty(ref _param, value)
可自动处理 INotifyPropertyChange
注:propp可快捷创建使用SetProperty(ref _param, value)
的属性
View示例代码
<UserControl x:Class="YourApp.Views.ViewA"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:YourApp.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel>
<TextBlock Text="This is ViewA" FontSize="24" Panel.ZIndex="-1"/>
<TextBlock Text="{Binding Message}" FontSize="24" Panel.ZIndex="-1"/>
</StackPanel>
<Button Content="Aletr" Height="100" Width="300" FontSize="24" Command="{Binding AlertCommand}"></Button>
<Button Content="Change To ViewB" Command="{Binding ChangeCommand}" Height="100" Width="300" FontSize="24" Grid.Row="1" ></Button>
</Grid>
</UserControl>
ViewModel示例代码
public class ViewAViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
private readonly IEventAggregator _eventAggregator;
public ViewAViewModel(IRegionManager regionManager, IEventAggregator eventAggregator)
{
_regionManager = regionManager;
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<MessageEvent>().Subscribe(ReceiveMessage);
}
public ICommand AlertCommand
{
get => new DelegateCommand(Alert);
}
public ICommand ChangeCommand
{
get => new DelegateCommand(Change);
}
private string _message = "None";
public string Message
{
get => _message;
set => SetProperty(ref _message, value);
}
private void Alert()
{
new Window().Show();
}
private void Change()
{
// 将MainRegion区域导航至ViewB
_regionManager.RequestNavigate("MainRegion", "ViewB");
}
private void ReceiveMessage(string message)
{
Message = message;
}
}