一 概述。

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内置有三种控件可以作为内容区域适配对象.

  1. ContentControl (内容控件)
  2. ItemsControl (集合控件)
  3. 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也有一些麻烦.