Prism Step2 Regions

Prism Step2 Regions

Prism 可以帮助我们开发模块化程序,将程序分割成一个个独立的 Module,分别进行开发。然后在程序运行的时候,将各个 Module 组合到一起,为程序提供各种各样的功能。通常来说,Module 是一些视图和功能的集合,那么就需要一种办法来将这些视图以某种形式,在特定的时间展现出来。Prism 通过 Shell + Region 来组织视图的布局,完成视图间的转换等。

Shell 相当于 ASP.NET 中的母版页,它定义了页面的布局、主题等。其中的导航区和内容区是预留出来的需要进行填充内容的部分,也就是 Region,起到占位符的作用,程序会在运行时动态地向 Region 中填充内容。

那么如何将一个区域定义为 Region 呢?

首先在引入 Prism 的命名空间

xmlns:prism=”http://www.codeplex.com/prism"

如果 IDE 无法找到这个命名空间的话,需要先注册 Prism,然后在需要定义为 Region 的控件上加上 Attached Property。

1
<ContentControl prism:RegionManager.RegionName="MainRegion" />

并不是所有的控件都可以作为 Region 的,需要为需要定义为 Region 的控件添加 RegionAdapter。RegionAdapter 的作用是为特定的控件创建相应的 Region,并将控件与 Region 进行绑定,然后为 Region 添加一些行为。一个 RegionAdapter 需要实现 IRegionAdapter 接口,如果你需要自定义一个 RegionAdapter,可以通过继承 RegionAdapterBase 类来省去一些工作。Prism 为 Silverlight 提供了几个 RegionAdapter:

ContentControlRegionAdapter
创建一个 SingleActiveRegion 并将其与 ContentControl 绑定

ItemsControlRegionAdapter
创建一个 AllActiveRegion 并将其与 ItemsControl 绑定

SelectorRegionAdapter
创建一个 Region 并将其与 Selector 绑定

TabControlRegionAdapter
创建一个 Region 并将其与 TabControl 绑定

通常我们并不直接和 Region 打交道,而是通过 RegionManager,它实现了 IRegionManager 接口。IRegionManager 接口包含一个只读属性 Regions,是 Region 的集合,还有一个 CreateRegionManager 方法。Prism 通过 RegionManagerExtensions 类使用扩展方法为 IRegionManager 添加了更多的功能。

AddToRegion
将一个视图添加到一个 Region 中。

RegisterViewWithRegion
将一个视图和一个 Region 进行关联。当 Region 显示的时候,关联的视图才会显示,也就是说,在这个 Region 显示之前,关联的视图是不会被创建的。

RequestNavigate
进行页面切换,将指定的 Region 中显示的视图切换为指定的视图。

本文开头说过,需要在运行时将分散在各个 Module 的视图显示在页面特定的位置上。那么首先就需要定义页面显示的地方,即 Region。然后就是要定义创建视图的时机和方式。在 Prism 中有两种方式来定义视图与 Region 之间的映射关系——View Discovery 和 View Injection。

如果一个页面相对来说不大变化,如导航区,在程序初始化的过程完成后就不会轻易地变动,这时候就较适合于使用 RegisterViewWithRegion 方法,通常可以在 Module 的 Initialize 方法中完成这个过程

1
2
3
4
5
6
7
8
public void Initialize()
{
logger.Log("初始化Navigation模块", Category.Debug, Priority.Low);
_regionManager.RegisterViewWithRegion(RegionNames.NavRegion, typeof(NavigationItem));
_regionManager.RegisterViewWithRegion(RegionNames.MainRegion, // 两种方式都可以
() => _container.Resolve<NavigationContainer>() );
_regionManager.RegisterViewWithRegion(RegionNames.NavDemoActionRegion, typeof(ActionController));
}

如果一个区域需要频繁地切换页面的话,如主内容区,可以使用 View Injection 的方式。

1
2
3
4
IRegionManager regionManager = ...;
IRegion mainRegion = regionManager.Regions["MainRegion"];
InboxView view = this.container.Resolve<InboxView>();
mainRegion.Add(view);

可以看到,这时候已经生成了视图的实例。之前提到过,一个 Region 可以包含多个视图,这些视图会处于不同的状态,对于 ItemsControl 类型的 Region 来说,里面会显示很多个 Item,所以添加进去就可以了;但是对于 ContentControl 这种 Region,同一时刻只能显示一个视图,所以在添加进去之后还需要有一个 Activate 的过程。

使用 URI 来进行导航只需要提供需要切换的视图的名称就可以,并不需要了解视图的类型,从而达到解耦的目的,并且可以通过 URI 来进行参数传递。

1
2
3
4
5
6
public void Initialize()
{
_container.RegisterType<object, ViewA>(ViewNames.ViewA);
_container.RegisterType<object, ViewB>(ViewNames.ViewB);
_container.RegisterType<object, ViewC>(ViewNames.ViewC);
}

评论