CAL:模块化应用程序入门指南:第 1 部分 (共 n 部分)






4.76/5 (21投票s)
一个更简单的系列,用于学习 Composite application library。
引言
有很多关于 Composite 的优秀文章;例如,来自 Daniel Vaughan 的 Calcium 文章,它们很棒,文档齐全,实现良好,等等……**但是**,它们非常复杂,我看到很多人因为现有文章的复杂性而放弃了对这项神奇技术的学习。嗯,这有点问题,对吧?伟大的技术应该让我们的生活更轻松,而不是带来如此多的复杂性,以至于我们要花费昼夜不停的时间才能理解要点。
Composite 有一个美好的目标,尽管关于它的说法,它非常容易理解和正确地投入使用;所以现在是时候放下闲聊,展望 WPF 和 Silverlight 应用程序的未来了。
摘要
由于这是 n 部分中的第 1 部分,因此本文集的内容可能会有所不同,但我的意图是遵循以下顺序
- 创建基本的 Composite WPF 应用程序(本文)
- CAL 中的命令(暂定名称)
- 创建自定义区域适配器(暂定名称)
- 日志策略(暂定名称)
- 多个开发团队,单个解决方案(暂定名称)
- 企业 CAL 应用程序的成本效益比考虑(暂定名称)
这样,我认为我们将涵盖基础知识,这将使我们能够更好地理解复杂文章的精彩实现。
先决条件
显然,我们需要获取一样东西,那就是 Composite Application Library。这是 Composite 网站。
在安装完 Composite Application Guidance pack 后,我强烈建议您阅读文档;我知道它很庞大,但值得花些时间研究。
实操
开始,您已经下载了 CAL 并已构建它,现在是时候开始玩您的新玩具了。所以让我们从基础开始。
CALient.Core
CALient.Core 是我们应用程序的核心,是它的灵魂,它是一个 WPF 应用程序,将成为我们 CAL 世界的中心。
让我们创建我们的解决方案。在我看来,创建 Composite 解决方案的最佳方法是创建一个 Visual Studio 空解决方案。为什么?因为您可以,并且将,在解决方案文件夹中组织您的解决方案;这样,您就可以更清楚地知道解决方案中的一切都在哪里。

如上图所示,从“其他项目类型”中选择“Visual Studio Solutions”,然后选择“Blank Solution”。这将字面上为您提供一个空白解决方案,如下所示。

现在,在解决方案内部,创建一个名为 _Client_ 的解决方案文件夹;在该文件夹内,您将创建一个新的 WPF 应用程序项目,并将其命名为 CAL.Core。
现在是时候考虑一些个人偏好,例如应用程序的核心。我认为应用程序的核心不是一个程序/可执行文件,而是一个库,所以您右键单击并打开项目的属性,然后您将看到以下屏幕。

在此选项卡上,只需将项目的输出类型更改为类库。现在,只需删除您的 _window1.xaml_ 和 _App.xaml_,您就不需要它们了。
现在,我们将向项目中添加我们将注册模块的区域名称,例如
namespace CALient.Core
{
    public class RegionMapping
    {
        public static string REGION_Content = "Region_Content",
            REGION_Menu = "Region_Menus";
    }
}
在此项目内,创建一个名为 _DesktopShell_ 的文件夹,并在其中添加一个名为 _Shell.xaml_ 的 Window。
然后,您添加 Composite Application Library 的引用,并在 _Shell.xaml_ 中添加以下行。
<Window 
    x:Class="CALient.Core.DesktopShell.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"    
    xmlns:CALient="clr-namespace:CALient.Core"
    Title="Shell" Height="300" Width="300">
    <DockPanel>
        <ItemsControl 
           CAL:RegionManager.RegionName="{x:Static CALient:RegionMapping.REGION_Menu}" 
           DockPanel.Dock="Top"/>
        <ContentControl 
           CAL:RegionManager.RegionName="{x:Static CALient:RegionMapping.REGION_Content}"/>
    </DockPanel>
</Window>
对于本文的范围,桌面 shell 已经准备就绪……非常简单,对吧?没有什么秘密。
现在应用程序才能正常工作,我们需要一个称为 Bootstrapper 的东西。它将扩展 Composite Application Library 中的 UnityBootstrapper,所以我们现在就来做。
class Bootstrapper : UnityBootstrapper
{
    protected override System.Windows.DependencyObject CreateShell()
    {
        var shell = new Shell();
        shell.Show();
        return shell;
    }
    protected override 
         Microsoft.Practices.Composite.Modularity.IModuleCatalog GetModuleCatalog()
    {
        // To be simpler to understand we use here
        // just a Directory Module Catalog that will search
        // for available modules in a certain directory,
        // in this case our application root directory
        var modules = new DirectoryModuleCatalog() { ModulePath = @"./" };
        return modules;
    }
}
现在,我们创建一个类来启动所有内容,如下所示。
public class ApplicationStarter
{
    public static void Run()
    {
        Bootstrapper b = new Bootstrapper();
        b.Run();
    }
}
太好了。核心已设置并准备就绪。
现在,让我们创建一个应用程序来启动它。
在 Client Solution 文件夹中创建另一个项目,命名为 CALient,删除 _Window1.xaml_,并在 _App.xaml_ 中删除 StartupURI="Window1.XAML"。添加对 CALient.Core 的引用,然后转到 _App.xaml.cs_ 并在 CTOR 方法中添加以下行。
public App()
{
    ApplicationStarter.Run();
}
运行它……然后砰!一个空白窗口 =D,所有这些只是为了一个空白窗口……是的,现在是时候构建有趣的部分了,也就是 Modules。
我该怎么做?
我们将这样做。让我们在名为 _Modules_ 的新解决方案文件夹中添加一个项目用于模块。在这个模块中,只需添加一个 WPF UserControl Library 并随意命名;在此项目中,它被命名为 CALient.One。
然后,您将删除 _UserControl1.xaml_ 并向这个新创建的程序集中添加一个类,将其命名为 _[name]Module_,您将得到以下内容。
打开文件并添加以下代码片段。
[Module(ModuleName = "Module One")]
public class OneModule : IModule
{
    IRegionManager regionManager;
    public OneModule(IRegionManager regionManager)
    {
        this.regionManager = regionManager;
    }
    public void Initialize()
    {
        regionManager.RegisterViewWithRegion(RegionMapping.REGION_Menu, typeof(MenuView));
    }
}
此模块将由三个视图和一个调用这 3 个视图的菜单组成,如下所示。



所以 MenuView 将是这样的。
<UserControl x:Class="CALient.One.MenuView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
    <StackPanel Orientation="Horizontal">
        <Button Margin="10" Width="100" Click="Button1_Click">
            <Button.Content>
                <Image Source="/CALient.One;component/Images/imgOK.png" />
            </Button.Content>
        </Button>
        <Button Margin="10" Width="100" Click="Button2_Click">
            <Button.Content>
                <Image Source="/CALient.One;component/Images/imgCancelar.png" />
            </Button.Content>
        </Button>
    </StackPanel>
</UserControl>
在代码隐藏中(因为我们的重点是解释这种方法,并且计划仅使用命令,在下一篇文章中,我们这里不使用命令,但如果您愿意,也可以使用它们 =D)
//... removed for clarity ...
UserControl current;
private IRegionManager regionManager;
public MenuView(IRegionManager regionMgr
{
    InitializeComponent();
    regionManager = regionMgr;
}
private void Button1_Click(object sender, RoutedEventArgs e)
{
    if(current != null)
        regionManager.Regions[RegionMapping.REGION_Content].Remove(current);
    current = new ModuleView1();
    regionManager.Regions[RegionMapping.REGION_Content].Add(current);
}
private void Button2_Click(object sender, RoutedEventArgs e)
{
    if (current != null)
        regionManager.Regions[RegionMapping.REGION_Content].Remove(current);
    current = new ModuleView2();
    regionManager.Regions[RegionMapping.REGION_Content].Add(current);
}
//... removed for clarity ...
另一个重要问题是,一旦我们构建了应用程序,模块将不会部署在正确的位置(根文件夹中);为此,您必须在模块项目的 Post-build event commandline 中添加以下行。
xcopy "$(TargetDir)*.*" "$(SolutionDir)CALient\bin\$(ConfigurationName)\" /Y
如您所见,我们的视图只是包含不同背景颜色和不同内容文本的静态 UserControls。
再次运行它。
现在,正如您通过再次运行解决方案所看到的,我们的解决方案已成功构建,通过单击 Module 的 MenuView 中的按钮,我们启动了视图,而不知道它是什么,或者它来自哪里;这就是 Composite 的美妙之处;最大限度的解耦开发。
完成
希望这对您有所帮助,并且您喜欢它。下次文章再见(希望这次会更快)。


