[7.1update]在开始前,我们先看下版本7.1中在本实例中的改动。
- 首先,项目文件中没有了
Bootstrapper.cs
,在上一篇的末尾,我们说过了,在7.1中,不见推荐使用Bootstrapper,相关改动整合到app.xaml和app.xaml.cs中。 - 然后:
app.xaml
<prism:PrismApplication x:Class="Regions.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" xmlns:local="clr-namespace:Regions"> <Application.Resources> </Application.Resources> </prism:PrismApplication>
在6.x中,这里还是一个Application
,现在已经改成prism:PrismApplication
然后是,App.xaml.cs
using Prism.Ioc; using Prism.Unity; using Regions.Views; using System.Windows; namespace Regions { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { } } }
这里用了 Prism.Ioc
和Prism.Unity
新的Prism.IoC命名空间,它创建了一个依赖注入容器的抽象。您现在只使用Prism提供的IContainerRegistry和IContainerProvider接口,而不是直接使用容器类。该IContainerProvider 接口用于从容器解析服务,IContainerRegistry 用于与容器登记类型。
而之前的Unity也不再使用了,现在使用Prism.Unity,上面App.xaml.cs
代码中 的PrismApplication 正是存在于Prism.Unity,如果你需要从6.x升级到7.x,所有的unity引用都需要删掉,重新添加Prism.Unity,并且修改相关代码。
0x3 Region
regions
Regions是应用程序UI的逻辑区域,它很像一个PlaceHolder,Views在Regions中展现,很多种控件可以被用作Region :ContentControl、ItemsControl、ListBox、TabControl。
简单的说,就是一个容器(区域适配器),用来装载Views的。这像WinForms中的Container控件Panel,里面可以放置其他控件。在PRISM中,Views也是用户控件(UserControl)
Region的注册方式:
? 在MainWindow.xaml
中:
<Window x:Class="Regions.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="Shell" Height="350" Width="525"> <Grid> <ContentControl prism:RegionManager.RegionName="ContentRegion" /> </Grid> </Window>
从这里开始,我们就不得不面对 XAML了。继续引用维基百科的介绍:
XAML(Extensible Application Markup Language)是Windows Presentation Foundation(WPF)的一部分,是微软开发的一种基于XML、基于声明,用于初始化结构化值和对象的用户界面描述语言,它有着HTML的外观,又揉合了XML语法的本质,例如:可以使用
<Button>
标签设置按钮Button。
(⊙﹏⊙)。。。
好,这个很简单,不需要介绍了。然后我们看代码,首先在头部引入命名空间xmlns:prism="http://prismlibrary.com/"
,这个prism是别名,你也可以像上面的x
一样将他命名成其他你想要的名字比如sm
??,当然了我们默认使用prism这样比较符合命名规范,然后在Grid控件里面,新建了了一个ContentControl,作为Region的目标,并且给他取了一个名字ContentRegion
。
由于更新7.1导致篇幅过长,这里将控件定制region单独摘了一篇:
是不是所有的控件都可以用来做Region呢?
注册视图
指定了Region,接下来就为Region指定View了。
在Views目录下面,新建一个UserControl,并在Grid控件内,加一个TextBlock,写上字,标识这是View A。
依旧省去了大部分头部引用,代码都是在Prism-Samples-Wpf里的,这里贴出来仅方便大家无源码阅读
<UserControl x:Class="ViewDiscovery.Views.ViewA" ... d:DesignHeight="300" d:DesignWidth="300"> <Grid> <TextBlock Text="View A" FontSize="38" /> </Grid> </UserControl>
我们现在想要,在上一小节制定的Region内显示View A,怎么做呢?我们来看MainWindow的code-behind,即:MainWindow.xaml.cs
using Prism.Regions; using System.Windows; namespace ViewDiscovery.Views { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow(IRegionManager regionManager) { InitializeComponent(); //view discovery regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA)); } } }
看上去,他只用了一行代码就实现了,在Region中显示ViewA。可仔细看一下,这好像哪不太一样。最早我们的MainWindow.xaml.cs的构造函数是没有参数的,这里多了一个IRegionManager
类型的参数regionManager,是不是很眼熟?
依赖注入容器
[7.1updated]虽然7.1不再使用Unity,但这不影响我们来了解依赖注入容器在prism中的作用
prism是使用依赖注入容器实现依赖注入的,这里我们使用的是Unity,Prism同样支持Mef容器实现依赖注入。[7.1updated]现已不再支持Mef容器了
如果使用 Unity 实例化一个类,该类的构造函数依赖一个或多个其他类,则 Unity 会为构造函数自动创建参数中指定的被依赖的类的实例。上面MainWindow的构造函数中的regionManager参数,就是Unity自动创建的。
参考:IoC 依赖注入容器 Unity
RegionManager
代码中RegionManager的RegisterViewWithRegion方法将我们的视图(View)和区域适配器(Region)进行关联
RegionManager,它实现了IRegionManager接口。IRegionManager接口包含一个只读属性Regions,是Region的集合(这个集合是从xaml中获取的,也就是我们定义的那些),RegionManager的实例会使用他们,并将view注册给他们。
View Discovery和View Injection
在Prism中有两种方式来定义视图与Region之间的映射关系——View Discovery和View Injection。
上面的regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA));
就是View Discovery。
然后我们看一下View Injection:
using Microsoft.Practices.Unity; using Prism.Regions; using System.Windows; namespace ViewInjection.Views { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { IUnityContainer _container; IRegionManager _regionManager; public MainWindow(IUnityContainer container, IRegionManager regionManager) { InitializeComponent(); _container = container; _regionManager = regionManager; } private void Button_Click(object sender, RoutedEventArgs e) { var view = _container.Resolve<ViewA>(); IRegion region = _regionManager.Regions["ContentRegion"]; region.Add(view); } } }
他从_regionManager中获取Region,然后使用IRegion.Add(View)的方式来向已有的Region中添加View。
视图的激活与取消激活
private void Button_Click(object sender, RoutedEventArgs e) { //activate view a _region.Activate(_viewA); } private void Button_Click_1(object sender, RoutedEventArgs e) { //deactivate view a _region.Deactivate(_viewA); }