[Prism]Composite Application Guidance for WPF(3)——创建第一个 Composite WPF Application

Author: 周银辉

1. 前提条件:

你需要下载到CAL (Composite application library ) 库,实际上就是几个DLL 文件,在项目中将会引用到他们来打造我们的程序,你可以从这里下载到它们。当然你也需要一个能打造WPF 应用的IDE ,比如VS2008 。

2 .创建Shell Project

         2.1 .在VS 中新建一个WPF Application ,将CAL 库文件添加到项目引用中

         2.2 .将自动生成的Window1 主窗口及其相应的文件重命名为Shell ,其将作为我们的Composite App 的Shell 。

         2.3 .创建Bootstrapper ,自定义程序初始化方式

                     新建一个Bootstrapper 类,让其继承于Unity Bootstrapper ,并重写其中的某些方法来实现我们的定制

internal class Bootstrapper : UnityBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            var shell = new Shell();
            shell.Show();
            return shell;
        }
        protected override IModuleEnumerator GetModuleEnumerator()
        {            
            return new StaticModuleEnumerator();
        }
}

我们通过重写CreateShell() 方法指定我们的Shell ,通过重写GetModuleEnumerator() 方法来指定我们的模块加载方式(这里为了编译通过,我们暂时返回一个StaticModuleEnumerator ,待会会介绍如何使用配置文件来配置模块的加载)

2.4 .修改程序启动方式

                     我们知道当新建一个WPF Application 时,VS 会在App.xaml 自动生成指定StartupUri 到主窗口,但这不是我们的Composite WPF Application 想要的方式,我们需要从Bootstrapper 启动,所以删除App.xaml 自动生成指定的StartupUri ,并重写App 类的构造方法:

public partial class App
    {
        public App()
        {
            var bootStrapper = new Bootstrapper();
            bootStrapper.Run();
        }
    }

F5 ,Shell 就可以RUN 起来啦

3 .创建Hello World 模块

         3.1 .在解决方案中添加一个新的项目“HelloWorldModule ”(暂且ClassLibrary 类型吧)

         3.2. 添加CAL 库到项目引用中,目前添加Microsoft.Practices.Composite 和Microsoft.Practices.Composite.Wpf 就可以了。

         3.3 .从语法层面讲,要实现一个Module ,需要实现IModule 接口,OK ,新建一个HelloWorldModule 类:

public class HelloWorldModule : IModule
    {        
        #region IModule Members
        public void Initialize()
        {           
            System.Windows.MessageBox.Show("this is hello module");
        }
        #endregion
}

我们这里为了避免扰乱读者视线,简化一下,就上该Module 显示一个MessageBox 就OK 了。

4 .将模块加载到Shell Project 中

我们可以看到Shell Project 和HelloWorld Project 是完全独立的两个项目,在实际开发中,它们可能是由两个不同的Team 独立开发和测试的。所以为了能在Shell 中使用HelloWord ,CAL 提供了多种方式来发现和加载模块,最简单的当然是静态加载即直接项目引用,我们这里采用配件文件的形式来实现(CAL 还提供了通过扫描文件夹的方式来加载)

4.1 .添加配置文件

回到Shell Project ,在该项目中添加Application Configuration File ,其会生成一个App.config 文件,在这个文件中我们可以配置系统模块组成结构、加载顺序以及模块之间的依赖性:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
    <section name="modules" type="Microsoft.Practices.Composite.Modularity.ModulesConfigurationSection, Microsoft.Practices.Composite"/>
 </configSections>
 <modules>
    <module assemblyFile="HelloWorldModule.dll" moduleType="HelloWorldModule.HelloWorldModule" moduleName="HelloWorldModule">
    </module>
 </modules>
</configuration>

4.2 .指定加载方式

然后回到我们的Bootstrapper 类,指定我们的模块加载方式为配置文件加载:

protected override IModuleEnumerator GetModuleEnumerator()
        {
            var configStory = new ConfigurationStore();
            return new ConfigurationModuleEnumerator(configStory);
        }

4.3 .指定模块生成位置

我们知道,模块的默认生成位置是项目的DEBUG (与RELEASE )目录,这会导致一个问题是:我们的Shell 项目不知道这些模块的生成文件位置从而找不到模块文件,所以我们可以通过模块项目的Build Events 中的Post-build event command line 来将生成的文件自动拷贝到Shell 项目的DEBUG (或RELEASE )目录下:

xcopy "$(TargetDir)*.*" "$(SolutionDir)CAG_HelloWorld\bin\$(ConfigurationName)" /Y

(其中CAG_HelloWorld 是Shell 项目的名称)

重新生成一下项目,F5 ,OK

5 .将模块中的View 注入到Shell 中

         在上面的示例中,我们仅仅在HelloWord 模块中,显示了一个MessageBox ,现在我们看看如何在其中加入一个View ,并在Shell 中显示出来

         5.1 .在Shell 中添加一个Region

                   回到Shell.xaml ,在其中添加一个容器控件作为一个Region ,你可以将Region 看做是一个占位符,其用于放置我们的View

<Window x:Class="CAG_HelloWorld.Shell"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cal="https://www.codeplex.com/CompositeWPF"
    Title="Shell" Height="300" Width="300">
    <Grid>
        <ItemsControl cal:RegionManager.RegionName="MainRegion"/>
    </Grid>
</Window>

5.2 .在HelloWord Project 中加入HelloWorldView

                   添加一个UserControl 到HelloWord Project 中(其实也可以是其他UI 元素),在上面任意显示点什么东西,比如一个带有HelloWord 字样的TextBlock 。其将作为我们的View 。

         5.3 .将View 注入到Region 中

         这项工作是由Module 在模块初始化来完成的。首先我们需要找到指定的View 要注入到Region ,而RegionManager 提供相应的功能:

         IRegion mainRegion = regionManager.Regions["MainRegion"];

         然后我们可以将我们的View 加到给Region 中并激活它了:

                  var view = new HelloWorldView();

                 mainRegion.Add(view);

mainRegion.Activate(view);

         总的说来,我们的HelloWorldModule 代码如下所示:

public class HelloWorldModule : IModule
    {
        private readonly IRegionManager regionManager;
        public HelloWorldModule(IRegionManager regionManager)
        {
            this.regionManager = regionManager;
        }
        #region IModule Members
        public void Initialize()
        {
            IRegion mainRegion = regionManager.Regions["MainRegion"]; 
            var view = new HelloWorldView();
            mainRegion.Add(view);
            mainRegion.Activate(view);
        }
        #endregion
}

OK ,至此,DEMO 打造完毕,当然这step by step 的打造会让人知其然不知其所以然,但问了不混淆视线,就没有引入CAL 的其他特性以及模块内部并没很好地遵循MVP 或MVC 等模式。

 

 

 

下一篇:[Prism]Composite Application Guidance for WPF(4) -- -- Bootstrapper-周银辉