Prism 是一个开源框架,专门用于开发可扩展、模块化和可测试的企业级 XAML 应用程序,适用于 WPF(Windows Presentation Foundation)和 Xamarin Forms 等平台。它基于 MVVM(Model-View-ViewModel)设计模式,提供一套丰富的工具和库,能够实现模块化、依赖注入、导航和事件聚合等功能。
Prism 的核心组件包括:
- 依赖注入(Dependency Injection):Prism 提供了一个依赖注入容器,可以将应用程序的组件和服务进行解耦,从而提高代码的可测试性和可维护性。
- 模块化(Modularity):Prism 支持模块化设计,将应用程序分解成独立的模块,每个模块负责特定的功能,有助于减少应用程序的复杂性,并能够使开发和维护更加容易。
- 导航(Navigation):Prism 提供了一个灵活的导航系统,可以定义视图之间的导航路径,并管理视图的生命周期。
- 事件聚合器(Event Aggregator):这是一个松散耦合的事件发布/订阅机制,应用程序的不同部分之间进行通信,而不需要直接引用对方。
- 命令(Commands):Prism 提供了一种简化的方式来处理用户界面中的命令,如按钮点击事件。
- 数据绑定(Data Binding):虽然 Prism 本身不提供数据绑定机制,但它与 WPF 和 Xamarin.Forms 的数据绑定框架紧密集成,可以轻松地将视图模型与视图进行绑定。
安装 Prism
Prism 可以通过 NuGet 包管理器进行安装,主要安装三个 Prism.Core、Prism.Unity、Prism.Wpf。首先创建一个新的 WPF、Xamarin Forms、Uno 或 WinUI 项目,然后打开 NuGet 包管理器,右键点击项目 -> 选择"管理 NuGet 包"。安装 Prism 核心包 Prism.Core
,安装容器包 Prism.Unity
或 Prism.DryIoc
(根据需求选择),然后安装平台包,例如 WPF 安装 Prism.Wpf
。
使用 Prism
在 WPF 项目中使用 Prism 时,需要进行以下步骤:
- 新建WPF项目:新建一个 WPF 项目,并根据上面完成 Prism 的安装。
- 重写 App.xaml:添加命名空间
xmlns:prism="http://prismlibrary.com/"
并继承PrismApplication
,删除StartupUri="MainWindow.xaml
。 - 修改 App.xaml.cs:继承
PrismApplication
,并重写CreateShell
和RegisterTypes
方法。CreateShell
方法返回应用程序的主窗口,RegisterTypes
方法用于注册需要的类型。 - 修改 MainWindow.xaml:添加命名空间
xmlns:prism="http://prismlibrary.com/"
并设置prism:ViewModelLocator.AutoWireViewModel="True"
,Prism 框架会根据规则自动查找该视图相对应 ViewModel。
通过这些步骤,你可以在 WPF 项目中集成 Prism 框架,实现 MVVM 架构和模块化开发。
priam的依赖注入
Prism 框架中的依赖注入(Dependency Injection)是一种实现控制反转(Inversion of Control, IoC)的机制,它允许开发者将组件和服务的创建和管理从应用程序代码中分离出来,从而提高代码的可测试性和可维护性。以下是 Prism 依赖注入的一些关键点:
-
PrismApplication 和依赖注入: Prism 项目中的
App
类继承自PrismApplication
,必须重写CreateShell()
和RegisterTypes()
方法。RegisterTypes()
方法用于依赖注入容器,该方法使用IContainerRegistry
类型的对象将用户自定义的对象注入容器。 -
内置依赖注入: Prism 源码中已经向 IoC 容器注入了一些核心服务,如
IApplicationProvider
、IEventAggregator
、INavigationService
等,这些服务可以在窗体中通过构造函数直接注入对象。 -
自定义服务注入: 如果需要将自定义服务注入 Prism 容器,可以在
App.xaml.cs
中重写RegisterTypes()
方法,通过IContainerRegistry
类型的对象将自定义的服务注入 IoC 容器。例如,注册一个MD5Provider
服务:protected override void RegisterTypes(IContainerRegistry containerRegistry) {containerRegistry.Register<MD5Provider>(); }
然后在需要使用该服务的地方,通过构造函数从 IoC 容器里将对象解析出来:
public IndexViewModel(IContainerExtension container) {MD5Provider provider = container.Resolve<MD5Provider>(); }
-
依赖注入的几种方法:
Register
:每次解析都会创建一个新的实例。RegisterSingleton
:整个应用程序生命周期内只创建一个实例(单例)。RegisterScoped
:在同一个 Scope 内只初始化一个实例。
-
模块化依赖注入: 可以为服务创建一个模块描述文件,继承接口
IModule
,在模块描述文件中进行依赖注入。然后在App.xaml.cs
中重写ConfigureModuleCatalog
方法加载模块,实现模块的整体注入。
prism的模块化
Prism 框架的模块化是一种将应用程序分解成独立、可重用模块的设计方法,这样可以提高应用程序的可维护性、可测试性和可扩展性。以下是 Prism 模块化的一些关键概念和步骤:
1. 模块的定义和特点
- 独立性:每个模块负责特定的功能,并且与其他模块保持低耦合。
- 可重用性:模块可以独立于主应用程序进行开发、测试和部署。
- 低耦合:模块之间的依赖关系最小化,有利于维护和扩展。
2. 模块的加载流程
加载模块的流程通常包括以下几个步骤:
- 注册模块:在应用程序中注册模块,以便 Prism 框架可以发现和加载它们。
- 发现模块:Prism 框架会根据注册信息发现模块。
- 加载模块:根据需要加载模块,可以是按需加载或在应用程序启动时加载。
- 初始化模块:模块被加载后,会进行初始化,完成模块的设置和配置。
3. 模块的注册方式
Prism 提供了多种模块注册方式:
- 代码注册:直接在代码中注册模块,这种方式简单直接,易于控制。
- 目录文件扫描注册:Prism 可以扫描指定目录下的模块并自动注册。
- 配置文件注册:通过配置文件(如
App.config
)来注册模块,这种方式可以在不修改代码的情况下调整模块的加载。
4. 模块的实现
一个典型的 Prism 模块实现包括以下几个部分:
- 模块类:实现
IModule
接口,定义模块的初始化和注册类型。 - 视图和视图模型:模块中包含的视图和视图模型,用于实现模块的用户界面和业务逻辑。
- 服务和依赖注入:在模块中注册服务,并使用依赖注入来管理这些服务。
5. 代码示例
以下是一个简单的 Prism 模块实现示例:
[Module(ModuleName = "MedicineModule", OnDemand = true)]
public class MedicineModule : IModule
{public void OnInitialized(IContainerProvider containerProvider){var regionManager = containerProvider.Resolve<IRegionManager>();regionManager.RegisterViewWithRegion(RegionNames.MedicineMainContentRegion, typeof(MedicineMainContent));}public void RegisterTypes(IContainerRegistry containerRegistry){// 在这里注册模块中需要的服务和类型}
}
在这个示例中,MedicineModule
类标记为一个 Prism 模块,并实现了 IModule
接口。在 OnInitialized
方法中,模块会注册视图到特定的区域。RegisterTypes
方法用于注册模块中需要的服务和类型,例如视图模型、服务等。
prism的导航
Prism 框架的导航机制是其核心功能之一,它允许应用程序在不同的视图(View)或视图模型(ViewModel)之间进行切换,以实现用户界面的动态更新和功能模块的加载。以下是 Prism 导航机制的一些关键点:
1. 导航的基本概念
Prism 的导航不依赖于页面(Page)实例,而是通过一个唯一的标识符或键(key)来实现松耦合的导航。这意味着在 Prism 中,你不是直接导航到一个视图或视图模型,而是导航到一个代表目标视图的唯一标识符。
2. 定义域(Region)
在 Prism 中,导航通常是基于区域(Region)的概念。你可以使用 ContentControl
、ItemsControl
及其子类来定义一个区域,并为这个区域命名。例如:
<ContentControl Grid.Row="1" Grid.ColumnSpan="2"prism:RegionManager.RegionName="ContentRegion"/>
这样,你就可以在代码中引用这个区域来进行导航。
3. 注册视图
在 Prism 中,你需要在依赖注入(DI)容器中注册视图,以便它们可以被导航到。Prism 提供了 RegisterTypeForNavigation
方法来实现这一点。例如,使用 Unity 容器注册视图:
_unityContainer.RegisterTypeForNavigation<CalendarView>();
这样,CalendarView
就可以被导航到了。
4. 导航操作
Prism 提供了 INavigationService
接口来处理导航请求。你可以通过调用 RequestNavigate
方法来导航到指定的视图。有两种主要的导航方式:
4.1 URI 导航
_regionManager.RequestNavigate("ContentRegion", calendarViewUri);
这里,ContentRegion
是目标区域的名称,calendarViewUri
是一个 Uri 类型的对象,表示需要导航到的视图的名称。
4.2 直接导航
你也可以直接通过视图的名称或自定义的键来导航:
_navigationService.NavigateAsync("MainPage");
这里的 "MainPage"
是注册时使用的键,用于标识要导航到的视图。
5. 自定义注册和导航
Prism 允许你自定义视图的注册和导航。你可以为视图提供一个唯一的键,而不是使用视图的名称作为键:
containerRegistry.RegisterForNavigation<MainPage>("CustomKey");
然后使用这个自定义的键来导航:
_navigationService.NavigateAsync("CustomKey");
这种方式提供了更多的灵活性,允许你根据需要自定义导航逻辑。
6. 跨平台导航
在跨平台应用中,Prism 允许你为不同的平台注册不同的视图,但使用相同的视图模型。这使得你可以为每个平台定制 UI,同时保持业务逻辑的一致性。
prism的事件聚合器(Event Aggregator)
Prism框架中的事件聚合器(Event Aggregator)是一种松散耦合的事件发布/订阅机制,它允许组件之间进行通信,而不需要直接引用对方。以下是Prism事件聚合器的一些关键特性和使用方法:
1. 松散耦合的通信
事件聚合器允许发布者(publishers)和订阅者(subscribers)通过事件进行通信,而不需要知道对方的存在。这种机制基于事件聚合服务,支持多播发布/订阅功能,即可以有多个发布者触发同一个事件,也可以有多个订阅者监听同一个事件。
2. 类型安全的事件
Prism中的事件是类型安全的,这意味着你可以利用编译时类型检查来在运行应用程序之前检测错误。事件聚合器允许订阅者或发布者定位到特定的EventBase
。
3. IEventAggregator接口
EventAggregator
类作为容器中的服务提供,可以通过IEventAggregator
接口检索。事件聚合器负责定位或构建事件,并维护系统中事件的集合:
public interface IEventAggregator
{TEventType GetEvent<TEventType>() where TEventType : EventBase;
}
EventAggregator
在首次访问时(如果尚未构建)会构建事件,这减轻了发布者或订阅者需要确定事件是否可用的负担。
4. PubSubEvent类
实际连接发布者和订阅者的工作由PubSubEvent
类完成。这是Prism库中唯一实现EventBase
类的类。这个类维护订阅者列表,并处理事件分发到订阅者。
5. 创建事件
PubSubEvent<TPayload>
是应用程序或模块特定事件的基类。TPayload
是事件负载的类型,即发布事件时传递给订阅者的参数。例如,以下代码展示了TickerSymbolSelectedEvent
,其负载是一个包含公司符号的字符串:
public class TickerSymbolSelectedEvent : PubSubEvent<string>{}
在复合应用程序中,事件通常在多个模块之间共享,因此它们被定义在一个公共位置,如“Core”或“Infrastructure”项目中。
6. 发布事件
发布事件时,你可以通过EventAggregator
获取事件实例,并调用Publish
方法来发布事件。例如:
IEventAggregator eventAggregator = container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<TickerSymbolSelectedEvent>().Publish("AAPL");
这样,所有订阅了TickerSymbolSelectedEvent
的订阅者都会收到事件,并执行相应的逻辑。
prism的命令(Commands)
Prism框架中的命令(Commands)机制是实现MVVM模式中用户交互与视图模型逻辑分离的核心。以下是Prism命令机制的一些关键点:
1. Prism命令的基础
Prism提供了两种主要的命令类型:
- DelegateCommand:一个简单的命令实现,适用于单个命令的场景。
- CompositeCommand:可以将多个命令组合在一起,适用于需要多个命令同时执行的场景。
2. 使用DelegateCommand
2.1. 创建视图模型
在视图模型中创建一个DelegateCommand
属性,指向一个方法。例如:
using Prism.Commands;
using Prism.Mvvm;public class MainViewModel : BindableBase
{public DelegateCommand MyCommand { get; private set; }public MainViewModel(){MyCommand = new DelegateCommand(OnMyCommandExecuted);}private void OnMyCommandExecuted(){// 命令执行时的逻辑System.Diagnostics.Debug.WriteLine("Command Executed!");}
}
2.2. 在XAML中绑定命令
在XAML中,可以将命令绑定到控件,如按钮:
<Button Content="Execute Command" Command="{Binding MyCommand}" />
这样,当按钮被点击时,就会执行绑定的命令。
3. 使用带参数的DelegateCommand
可以使用DelegateCommand<T>
来处理命令参数。例如:
public DelegateCommand<string> MyParameterizedCommand { get; private set; }public MainViewModel()
{MyParameterizedCommand = new DelegateCommand<string>(OnMyParameterizedCommandExecuted);
}private void OnMyParameterizedCommandExecuted(string parameter)
{// 使用传递的参数System.Diagnostics.Debug.WriteLine($"Command Executed with parameter: {parameter}");
}
在XAML中绑定参数:
<Button Content="Execute with Parameter"Command="{Binding MyParameterizedCommand}"CommandParameter="Hello World" />
这样,当按钮被点击时,就会执行绑定的命令,并传递参数。
4. 使用CompositeCommand
CompositeCommand
允许你将多个命令组合在一起,使得它们可以一起执行。例如:
public CompositeCommand MyCompositeCommand { get; private set; }
public DelegateCommand Command1 { get; private set; }
public DelegateCommand Command2 { get; private set; }public MainViewModel()
{MyCompositeCommand = new CompositeCommand();Command1 = new DelegateCommand(OnCommand1Executed);Command2 = new DelegateCommand(OnCommand2Executed);MyCompositeCommand.RegisterCommand(Command1);MyCompositeCommand.RegisterCommand(Command2);
}private void OnCommand1Executed()
{// 命令 1 执行逻辑
}private void OnCommand2Executed()
{// 命令 2 执行逻辑
}
在XAML中使用CompositeCommand
:
<Button Content="Execute Composite Command" Command="{Binding MyCompositeCommand}" />
这样,当按钮被点击时,就会同时执行Command1
和Command2
。
prism的数据绑定(Data Binding)
Prism框架本身并不提供数据绑定的实现,因为它是建立在WPF、Xamarin.Forms、UWP等框架之上的,这些框架已经内置了数据绑定的功能。Prism通过与这些框架的集成,使得开发者可以利用它们强大的数据绑定机制来构建MVVM(Model-View-ViewModel)模式的应用程序。以下是Prism与数据绑定相关的一些关键点:
1. MVVM模式与数据绑定
MVVM模式是Prism推荐的架构模式,它将用户界面(View)与业务逻辑(ViewModel)分离,并通过数据绑定将它们连接起来。在MVVM中,View只负责显示,ViewModel包含业务逻辑和数据,数据绑定负责在View和ViewModel之间同步数据。
2. WPF中的数据绑定
在WPF中,数据绑定是通过Binding
表达式实现的。例如,如果你想将一个文本框(TextBox)的Text
属性绑定到ViewModel的Name
属性,你可以这样写:
xml
<TextBox Text="{Binding Name}" />
Prism通过ViewModelLocator
自动或手动将ViewModel与View关联起来,从而实现数据绑定。
3. Xamarin.Forms中的数据绑定
Xamarin.Forms也支持数据绑定,语法与WPF类似。例如:
xml
<Entry Text="{Binding Name}" />
Prism通过ViewModelLocator
和BindingContext
将ViewModel与页面(Page)关联起来。
4. Prism的ViewModelLocator
ViewModelLocator
是Prism提供的一个附加属性,用于自动将ViewModel与View关联起来。例如,在WPF中,你可以在XAML中这样设置:
xml
<Window ...xmlns:prism="http://prismlibrary.com/"prism:ViewModelLocator.AutoWireViewModel="True"><!-- UI elements -->
</Window>
这样,Prism会自动创建ViewModel实例,并将其设置为View的DataContext
。
5. 数据转换
Prism与数据绑定框架一起使用时,可以利用数据转换器(Value Converters)来转换绑定的数据。例如,在Xamarin.Forms中,你可以创建一个转换器将布尔值转换为字符串:
csharp
public class BoolToStringConverter : IValueConverter
{public object Convert(object value, Type targetType, object parameter, CultureInfo culture){return (bool)value ? "Yes" : "No";}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){throw new NotImplementedException();}
}
然后在XAML中使用这个转换器:
xml
<Label Text="{Binding IsEnabled, Converter={StaticResource BoolToStringConverter}}" />
6. 命令绑定
Prism还支持命令绑定,允许你将UI元素(如按钮)的事件绑定到ViewModel中的命令。例如,在WPF中:
xml
<Button Command="{Binding SaveCommand}" Content="Save" />
这样,当按钮被点击时,就会执行ViewModel中的SaveCommand
。