周银辉
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="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="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等模式。