一 概述。
1 prism通过一个名为Bootstrapper类作为引导程序,引导shell
如下
internal class Bootstrapper : UnityBootstrapper
{
protected override IModuleCatalog GetModuleCatalog()
{
return new ModuleCatalog()
.AddModule(typeof(HelloWorldModule)); // 实现了IModule 用来加载呈现模块view ,程序的组成模块
}
protected override DependencyObject CreateShell()
{
Shell shell = new Shell(); // shell 如同母版页面,主窗口。
shell.Show();
return shell;
}
}
2 被引导的Windows称为窗体Shell ,
prism框架的加入,运行主窗体的方式改变了.因为prism要在窗体运行之前做一堆事情,来为框架可以做的事情做铺垫.所以我们要去掉StartupUri,手动启动窗体
app.cs 代码如下
public App()
{
Bootstrapper bootStrapper = new Bootstrapper();
bootStrapper.Run();
}
3 附加的内容区域Region, Region与asp.net母版页的ContentPlaceHolder的意义是相同的
4 被拆分的模块Module.定义好Region内容区域以后,可以在Region中加载不同的模块的用户控件.每个模块都有着不同功能,一个功能强大的应用程序就是由不同的模块组成的.将应用程序的不同功能,拆分成不同的小模块开发,复杂度明显就会降低.
5 prism内置有三种控件可以作为内容区域适配对象.
- ContentControl (内容控件)
- ItemsControl (集合控件)
- Selector (集合控件)
看起来只有三个,但是只要是继承自这三个控件的其他控件也可以,如TabControl,DockPanel,Selector等。
prism注册的命名空间 http://www.codeplex.com/CompositeWPF
二 实例
用RegionManager的附加属性RegionName注册了一个名叫MainRegion的内容区域
下面是shell 窗体的代码(Bootstrapper 引导的类)
<Window x:Class="HelloWorldSample.Shell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:cal="http://www.codeplex.com/CompositeWPF" Title="Composite Application Library Sample" Width="400" Height="300"> <ContentControl cal:RegionManager.RegionName="MainRegion"/> </Window>
通过IRegionManager获取已注册的内容区域
IRegion mainRegion = this.regionManager.Regions["MainRegion"];
在Region中添加内容
首先定义一个用户控件
<UserControl x:Class="HelloWorld.Views.HelloWorldView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid> <TextBlock Text="Hello World" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock> </Grid> </UserControl>
通过IRegion的Add方法添加用户控件.以下是一个简单模块的完成代码,当这个模块加载时,会默认执行Initialize方法.
public class HelloWorldModule : IModule { private readonly IRegionManager regionManager; public IUnityContainer container { get; set; } public HelloWorldModule(IRegionManager regionManager, IUnityContainer container) { this.regionManager = regionManager; this.container = container; } public void Initialize() { RenderHelloWorldView(); } void RenderHelloWorldView() { IRegion mainRegion = this.regionManager.Regions["MainRegion"]; mainRegion.Add(new HelloWorldView()); } }
下图表达以上三个步骤的意思. (view 表示用户控件)
Region对View(用户控件)的操作
1 添加
IRegionManager Add(object view);
IRegionManager Add(object view, string viewName);
IRegionManager Add(object view, string viewName, bool
createRegionManagerScope);
2 删除
void Remove(object view);
3 获取
object GetView(string viewName);
2.激活和停用View
默认情况下,当一个View添加到Region当中,都被记做是处于活动状态。IRegion提供了2个集合和2个方法来控制View的活动状态.
Activate方法将View转为可活动状态,Deactivate方法则冻结了View的使用.两个方法的调用将使Views和ActiveViews两个集合属性发生变化.
IViewsCollection实现了INotifyCollectionChanged接口了,所以当集合发生变化时会触发一个事件来引发ui界面发生变化,
这个事件的引发由Region和控件的适配器来完成。
注册子区域Region
在Region中添加的View同时也可以注册Region的,但这个被添加的View必须依靠依赖注入的功能才可以.
<UserControl x:Class="HelloWorld.Views.HelloWorldViewAgain" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:cal="http://www.codeplex.com/CompositeWPF" Height="300" Width="300"> <Grid> <StackPanel> <TextBlock Text="HelloWorldViewAgain"></TextBlock> <TextBlock Text="HelloWorldView Loading"></TextBlock> <ItemsControl cal:RegionManager.RegionName="HelloWorldViewAgain"/> <TextBlock Text="HelloWorldView Loaded"></TextBlock> </StackPanel> </Grid> </UserControl>
在Shell的Region中添加HelloWorldViewAgain(hellowordModle 中)
void RenderHelloWorldViewAgain() { IRegion mainRegion = this.regionManager.Regions["MainRegion"]; HelloWorldViewAgain viewAgain = container.Resolve<HelloWorldViewAgain>(); mainRegion.Add(viewAgain, "MainRegion"); viewAgain.DisplayHelloWorldView();// 依赖注入的功能 }
具体实现方法如下。
public void DisplayHelloWorldView()
{
var view=this.regionManager.Regions["MainRegion"].GetView("HelloWorldViewAgain") as DependencyObject;
IRegion region=RegionManager.GetRegionManager(view).Regions["HelloWorldViewAgain"];
region.Add(new HelloWorldView(), "hello");
}
下图表达了以上步骤的意思。
设定RegionManager的管理范围
<ContentControl x:Name=”panel” cal:RegionManager.RegionName="MainRegion"/>
这个Regions属性属于ContentControl的附加属性,可以通过RegionManager的GetRegionManager方法获取该控件的Region集合.
如
void RenderHelloWorldView()
{
IRegion mainRegion = this.regionManager.Regions["MainRegion"];
var view = new HelloWorldView();
mainRegion.Add(view);
}
public void DisplayHelloWorldView()
{
var view=this.regionManager.Regions["MainRegion"].GetView("HelloWorldViewAgain") as DependencyObject;
IRegion region=RegionManager.GetRegionManager(view).Regions["HelloWorldViewAgain"];
region.Add(new HelloWorldView(), "hello");
}
回头再看上面的一个Add方法.
IRegionManager Add(object view, string viewName, bool createRegionManagerScope);
在添加Region中添加一个View的时候,你可以指定是否重新设定RegionManager的范围.如果设置为True的话,将会调用CreateRegionManager方法为当前的View重新创建一个RegionManager.这就说明了如果创建的View中注册了一个Region,改Region是不知道其存在哪个RegionManager里面的.
现在我们重新更改上面的RenderHelloWorldViewAgain方法,添加View时,
第三个参数设置为True,如下
void RenderHelloWorldViewAgain() { IRegion mainRegion = this.regionManager.Regions["MainRegion"]; HelloWorldViewAgain viewAgain = container.Resolve<HelloWorldViewAgain>(); mainRegion.Add(viewAgain, "HelloWorldViewAgain",true); // 重新建立了RegionManager viewAgain.DisplayHelloWorldView(); }
这时HelloWorldViewAgain这个View已注册的Region,就很难知道其在哪个RegionManager,现在DisplayHelloWorldView方法更改如下
public void DisplayHelloWorldView() { var view=this.regionManager.Regions["MainRegion"].GetView("HelloWorldViewAgain") as DependencyObject; IRegion region=RegionManager.GetRegionManager(view).Regions["HelloWorldViewAgain"]; region.Add(new HelloWorldView(), "hello"); }
这种做法虽然可以避免Region重名等一些问题,但为获取Region的RegionManager也有一些麻烦.