Prism介绍
Prism是一个框架,用于在WPF、Xamarin Forms、Uno Platform和WinUI中构建松散耦合、可维护和可测试的XAML应用程序。
设计目标
为了实现下列目的:
创建能够由模块组成的程序,这些模块能够被单独地编写、组装、部署,并且对于程序来说是可选的
最小化团队之间的依赖,让每个团队专注与特定的领域。比如UI、逻辑代码实现或者是架构代码的开发。
通过架构提高不同团队之间的复用能力
通过抽象团队通用服务提高程序质量
迭代添加新的功能
Prism被设计用来帮助你设计和实现丰富、灵活、易于维护的WPF程序。Prism实现了多种设计模式,突出架构设计的松耦合、关注点分离等原则。使用设计模式和Prism提供的额能力,你可以通过独立开发的松耦合组件轻松的集成到整个应用程序中,从而开发一个应用程序。
Prism围绕架构原则的分散关注点和松耦合原则而设计的。这使得Prism提供能一下的好处:
重用。Prism通过允许组件和服务能够轻松的被开发、测试、集成到一个或多个程序来实现重用。组件级别的复用是通过依赖注入来轻松地发现和集成单元测试级别的组件。应用级别的复用是重用封装了应用级别能力的模块。
可扩展。Prism通过管理组件依赖,允许组件在运行时很容易地被集成或者被其他实现所替换,使得程序能够很容易地被扩展。并且将程序分解到模块,使得模块能够独立地更新和部署。Prism库中的许多组件本身就可以被扩展或者是替换。
灵活。Prism通过允许像开发集成新能力一样更新功能。Prism还允许WPF程序使用通用服务和组件开发,允许程序以最适当地方式去部署和使用。还允许程序基于不同的角色和配置,提供不同的使用功能。
团队开发。Prism促进团队开发,通过允许不同的团队单独开发甚至部署不同的应用程序部分。通过让团队专注于不同的功能领域或业务功能领域来减少团队之间的依赖。
质量。Prism通用让开发团队充分地测试服务和组件提高程序质量。此外,由于通用服务和组件都被完全地测试过了,开发团队能够专注于程序需求而不是如何实现和测试基础代码。
IoC:是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
按照以上思想设计的框架都叫IoC,它只是这一类框架的总称。IoC的框架有很多种例如MEF、Autofac、Castle Windsor、Unity。
初学可简单理解为有两个部分组成一个业务容器,和若干个业务模块组成。都塞到容器中进行管理。
Plug:是业务划分独立出的模块,里面具体的业务实现和常规的MVVM一样。
前置知识点
后续学习需掌握以下知识点:
Prism概念: Shell、 Modules、 Region、 Navigation、MVVM、 EventAggregator、 Services等。(本系列会学习这些)
IoC概念:需要知道整个框架是如何组成,思想是什么。
其他概念:C#、WPF、 MVVM。(默认已掌握)
Prism概览
- Application:我们开发应用程序,初始化Bootstrapper。
- Bootstrapper:是用来初始化应用程序级别的组件和服务,它也被用来配置和初始化module catalog和Shell 的View和View Model。
- Modules:是能够独立开发、测试、部署的功能单元,Modules可以被设计成实现特定业务逻辑的模块(如Profile Management),也可以被设计成实现通用基础设施或服务的模块。
- Shell是宿主应用程序(host application),modules将会被load到Shell中。Shell定义了应用程序的整体布局和结构,而不关心寄宿其中的Module,Shell通常实现通用的application service和infrastructure,而应用的逻辑则实现在具体的Module中,同时,Shell也提供了应用程序的顶层窗口。
- Services:是用来实现非UI相关功能的逻辑,例如logging、exception management、data access。Services可以被定义在应用程序中或者是Module中,Services通常被注册在依赖注入容器中,使得其它的组件可以很容易的定位这个服务。
- Container:注入服务、其他模块依赖。
需结合建好的Prism项目结构进行理解。
Region、 RegionManager、RegionAdapter
Region是应用程序UI的逻辑区域(具体的表现为容器控件),Views在Region中展现,很多种控件可以被用作Region:ContentControl、ItemsControl、ListBox、TabControl。Views能在Regions编程或者自动呈现,Prism也提供了Region导航的支持。这么设计主要为了解耦让内容显示灵活具有多样性。
RegionManager主要实现维护区域集合、提供对区域的访问、合成视图、区域导航、定义区域。
区域定义方式有两种:
· Xaml实现
<ContentControl x:Name=“ContentCtrl” prism:RegionManager.RegionName="ContentRegion" />
RegionManager.SetRegionName(ContentCtrl,”ContentRegion”);
· C#实现
public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
_regionManager.RegisterViewWithRegion("ContentRegion", typeof(MainWindow));
}
区域访问:
var contentRegion = _regionManager.Regions["ContentRegion"];
RegionAdapter(区域适配)主要作用为特定的控件创建相应的Region,并将控件与Region进行绑定,然后为Region添加一些行为。
因为并不是所有的控件都可以作为Region的,需要为需要定义为Region的控件添加RegionAdapter。
一个RegionAdapter需要实现IRegionAdapter接口,如果你需要自定义一个RegionAdapter,可以通过继承RegionAdapterBase类来省去一些工作。
Prism为开发者提供了几个默认RegionAdapter:
ContentControlRegionAdapter: 创建一个SingleActiveRegion并将其与ContentControl绑定
ItemsControlRegionAdapter: 创建一个AllActiveRegion并将其与ItemsControl绑定
SelectorRegionAdapter: 创建一个Region并将其与Selector绑定
TabControlRegionAdapter: 创建一个Region并将其与TabControl绑定
Module
具有特定功能,且独立存在则称为成为模块。
注册/发现模块:1.怎么发现? 2.哪里发现? 3.发现什么?
加载模块
初始化模块
Navigation – 视图导航
当用户与丰富的客户端应用程序交互时,其用户界面 (UI)将不断更新,以反映用户正在处理的当前任务和数据。随着时间的推移,随着用户与应用程序内的交互并完成各种任务,UI 可能会发生相当大的变化。应用程序协调这些 UI 更改的过程通常称为导航,这一过程由INavigationAware做支撑。
应用场景:View之间传值、需要在导航过程做操作(例如及时释放资源)。
- OnNavigatedFrom: 导航离开当前页面前, 此处可以传递过来的参数以及是否允许导航等动作的控制。
- IsNavigationTarget: 是否创建新示例。为true的时候表示不创建新示例,页面还是之前的;如果为false,则创建新的页面。
- OnNavigatedTo: 导航到当前页面前, 此处可以传递过来的参数以及是否允许导航等动作的控制。
Navigation – 确认导航(拦截)
您经常会发现您需要在导航操作期间与用户进行交互,以便用户可以确认或取消它。例如,在许多应用程序中,用户可能会尝试在输入或编辑数据时进行导航。在这些情况下,您可能需要询问用户是否希望保存或丢弃在继续从页面中导航之前已输入的数据,或者用户是否希望完全取消导航操作。
- 这些特性由IConfirmNavigationRequest做支撑,它融入了AOP(面向切面编程)的思想。
- 应用场景:权限管理、检测用户行为(页面停留多久、哪个模块访问次数最多等)、日志记录等。
Navigation - 导航日志
导航日志其实就是对导航系统的一个管理功能,理论上来说,我们应该知道我们上一步导航的位置、以及下一步导航的位置,包括我们导航的历史记录。以便于我们使用导航对应用程序可以灵活的控制。类似于我们熟知的双向链表结构。
导航日志由IRegionNavigationJournal提供支撑。
IRegionNavigationJournal接口有如下功能:
GoBack() : 返回上一页
CanGoBack: 是否可以返回上一页
GoForward(): 返回后一页
CanGoForward: 是否可以返回后一页