应网友要求提前介绍 Smart Client Software Factory 中的 Visualizer 的使用及自定义。

一、Smart Client Software Factory 中的 Visualizer 机制简介

Smart Client Software Factory 构建的客户端应用耦合松散,带来的问题是过于动态,我们很难通过简单的阅读源代码来把握 SCSF 应用的运行时状态,例如当前已经创建了哪些 WorkItem,WorkItem 里有注册了哪些 Services 和 Commands,WorkItem 的运行时层次结构是个什么样子。

想来 SCSF 团队应该也注意到了这个问题,因此引入了 Visualizer 工具来帮助我们很容易的看到 SCSF 应用运行时的具体状态。本文使用了 Codeplex 上的 CABWorkItemVisualizations 。

看看效果:

visualize_embedding函数 visualizer_Software

                   

visualize_embedding函数 visualizer_Software_02

visualize_embedding函数 visualizer_初始化_03

   

visualize_embedding函数 visualizer_自定义_04

  

visualize_embedding函数 visualizer_自定义_05

      

visualize_embedding函数 visualizer_初始化_06

    

visualize_embedding函数 visualizer_Software_07

      

visualize_embedding函数 visualizer_Software_08

    

visualize_embedding函数 visualizer_Software_09

 

最上面两个图片是整个监控界面,下边 6  幅图片是内部的具体视图,例如 分别是 WorkItems,Events,Items ,Services,States,Workspaces。最后一幅是执行操作后在当前 workItem 中又添加了新 WorkItem 的情况。

二、使用 Visualizer 监控 Smart Client Software Factory 应用的内部状态

使用 Visualizer 监控 SCSF 很简单,基本上通过简单的配置就可以。我们通过使用 CABWorkItemVisualizations 来演示如何在 SCSF 中启动并使用 Visualizer 。

第一步,引入 dll
可以在项目中引入这些 dll,也可以直接将这些 dll 拷贝到目标目录(应用程序目录,比如 bin)。

第二部,配置 Visualizer:


 1


visualize_embedding函数 visualizer_Software_10

<

configuration >


 2

visualize_embedding函数 visualizer_Software_10

  

< configSections >


 3

visualize_embedding函数 visualizer_Software_10

    

< section  name ="CompositeUI"  type ="Microsoft.Practices.CompositeUI.Configuration.SettingsSection, Microsoft.Practices.CompositeUI"  allowExeDefinition ="MachineToLocalUser"   />


 4

visualize_embedding函数 visualizer_Software_10

  

</ configSections >


 5

visualize_embedding函数 visualizer_Software_10

  

< CompositeUI >


 6

visualize_embedding函数 visualizer_Software_10

    

< visualizer >


 7

visualize_embedding函数 visualizer_Software_10

      

< add  type ="CABWorkItemVisualizations.FormVisualizer, CABWorkItemVisualizations"    />   <!--  直接使用 CABWorkItemVisualizations 提供的 dll  -->


 8

visualize_embedding函数 visualizer_Software_10

    

</ visualizer >


 9

visualize_embedding函数 visualizer_Software_10

  

</ CompositeUI >


10

visualize_embedding函数 visualizer_Software_10


</ configuration >

 

值得注意的是,如果使用源代码(引入项目的方式),配置中 type 应该是 “CABWorkItemVisualizations.WorkItemVisualization


visualize_embedding函数 visualizer_Software_10

   <

CompositeUI >

visualize_embedding函数 visualizer_Software_10

     <

visualizer >

visualize_embedding函数 visualizer_Software_10

       <

add  type ="CABWorkItemVisualizations.WorkItemVisualization, CABWorkItemVisualizations"    />   <!--  使用 CABWorkItemVisualizations 源代码  -->

visualize_embedding函数 visualizer_Software_10

     </

visualizer >

visualize_embedding函数 visualizer_Software_10

   </

CompositeUI >


如果一切正常,上面看到的 CAB Visualizer 就可以出现了。

三、研究 Smart Client Software Factory 中 Visualizer 的工作原理,创建自定义 Visualizer

使用 Visualizer 很简单,不需要知道它的具体工作原理,如果希望深入研究或者希望创建自定义 Visualizer,请继续阅读。

Visualizer 在 SCSF 框架启动过程中创建(具体在 CabShell 的 Run 方法中创建):


visualize_embedding函数 visualizer_Software_10

//  CabApplication 的 Run 方法中

visualize_embedding函数 visualizer_Software_10

IVisualizer visualizer  =

 CreateVisualizer();

 

CreateVisualizer 利用 VisualizerType (protected 属性)类型通过反射创建具体的 Visualizer ,是一个模板方法。

VisualizerType 属性在 WindowsFormsApplication (CabApplication 的子类)中指定为 WinFormsVisualizer


visualize_embedding函数 visualizer_Software_10

//  WindowsFormsApplication 在构造函数中设置了 VisualizerType ,供 CreateVisualizer() 使用

visualize_embedding函数 visualizer_Software_10

protected  WindowsFormsApplication()

visualize_embedding函数 visualizer_自定义_29

visualize_embedding函数 visualizer_初始化_30


visualize_embedding函数 visualizer_Software_31

{

visualize_embedding函数 visualizer_初始化_32

    Application.EnableVisualStyles();

visualize_embedding函数 visualizer_初始化_32

    VisualizerType = typeof(WinFormsVisualizer);// 创建的实际 IVisualizer 类型是 WinFormsVisualizer 继承自 CabVisualizer

visualize_embedding函数 visualizer_Software_34

}

 

IVisualizer 实例创建后,进行初始化(在 CabApplication 启动过程中)


visualize_embedding函数 visualizer_Software_10

//  CabApplication 的 Run 方法中

visualize_embedding函数 visualizer_Software_10

if  (visualizer  !=  

null )

visualize_embedding函数 visualizer_Software_10

    visualizer.Initialize(rootWorkItem, builder);

 

CabVisualizer 的初始化过程如下:


visualize_embedding函数 visualizer_初始化_38visualize_embedding函数 visualizer_自定义_39Code

visualize_embedding函数 visualizer_Software_10

//CabVisualizer 中

visualize_embedding函数 visualizer_Software_10

public void Initialize(WorkItem cabRootWorkItem, Builder cabBuilder)

visualize_embedding函数 visualizer_自定义_29

visualize_embedding函数 visualizer_初始化_30

visualize_embedding函数 visualizer_Software_31

{

visualize_embedding函数 visualizer_初始化_32

    if (this.cabRootWorkItem != null)

visualize_embedding函数 visualizer_初始化_32

throw new InvalidOperationException(Properties.Resources.VisualizerAlreadyInitialized);

visualize_embedding函数 visualizer_初始化_32


visualize_embedding函数 visualizer_初始化_32

    this.cabRootWorkItem = cabRootWorkItem; // 与 SCSF 应用共享一个 RootWorkItem

visualize_embedding函数 visualizer_初始化_32

    this.cabBuilder = cabBuilder;    Builder builder = CreateBuilder(); // 拥有 CAB 的 Builder 同时创建了自己的 Builder 。

visualize_embedding函数 visualizer_初始化_32

    AddBuilderStrategies(builder);

visualize_embedding函数 visualizer_初始化_32

    CreateRootWorkItem(builder);

visualize_embedding函数 visualizer_初始化_32

    AddRequiredServices();

visualize_embedding函数 visualizer_初始化_32

    AddServices();

visualize_embedding函数 visualizer_初始化_32


visualize_embedding函数 visualizer_初始化_32

    rootWorkItem.BuildUp();

visualize_embedding函数 visualizer_初始化_32

    CreateVisualizationShell(); //子类 WinFormsVisualizer 重写了该方法,在其中创建并显示了 VisualizerForm ,见下面

visualize_embedding函数 visualizer_初始化_32

    LoadVisualizerPlugins();

visualize_embedding函数 visualizer_初始化_32


visualize_embedding函数 visualizer_初始化_32

    rootWorkItem.Run();

visualize_embedding函数 visualizer_Software_34


初始化的核心过程是创建了自己的 Builder 并构造了自己的 RootWorkItem ,因此可以与我们的 SCSF 应用(被监控的应用)并行执行。随后创建 Visualizer 主窗体,并将 Visualizer 插件加载到主窗体中。


visualize_embedding函数 visualizer_Software_10

// WinFormsVisualizer 中,创建 Visualizer 主窗体,这里是 VisualizerForm

visualize_embedding函数 visualizer_Software_10

protected   override   sealed  

void  CreateVisualizationShell()

visualize_embedding函数 visualizer_自定义_29

visualize_embedding函数 visualizer_初始化_30


visualize_embedding函数 visualizer_Software_31

{

visualize_embedding函数 visualizer_初始化_32

    RootWorkItem.Items.AddNew<VisualizerForm>("VisualizerForm").Show();

visualize_embedding函数 visualizer_Software_34

}

 

VisualizerForm (用于显示监控界面的主窗体)位于 namespace Microsoft.Practices.CompositeUI.WinForms.Visualizer ,是一个 internal 类,只在 SCSF 内部使用:


internal   partial   class  VisualizerForm : Form


该 Form 的名字是 "MainWorkspace" ,提供给自定义的 Visualizer 使用:


this .MainWorkspace.Name  =   " MainWorkspace " ;


然后加载在配置文件中指定的具体 Visualizer 插件,插件在创建后应该主动加载到 VisualizerForm 主窗体中。


visualize_embedding函数 visualizer_Software_10

// CabVisualizer 中

visualize_embedding函数 visualizer_Software_10

private   void  LoadVisualizerPlugins()

visualize_embedding函数 visualizer_自定义_29

visualize_embedding函数 visualizer_初始化_30


visualize_embedding函数 visualizer_Software_31

{

visualize_embedding函数 visualizer_初始化_32

    foreach (VisualizationElement elt in Configuration)

visualize_embedding函数 visualizer_初始化_32

        AddNewVisualization(elt.Type);

visualize_embedding函数 visualizer_Software_34

}

 

我们看看上面使用到的 CABWorkItemVisualizations 中 Visualizer 插件是如何具体实现的


visualize_embedding函数 visualizer_Software_10

//  WorkItemVisualization 是一个可以承载在 Form (或 WPF)中的用户控件

visualize_embedding函数 visualizer_Software_10

public   partial   class  WorkItemVisualization : UserControl

 


 1

visualize_embedding函数 visualizer_Software_10

//  WorkItemVisualization 的注入式构造函数,上面的 AddNewVisualization 中使用

 2

visualize_embedding函数 visualizer_Software_10

[InjectionConstructor]

 3

visualize_embedding函数 visualizer_Software_10

public  WorkItemVisualization( IVisualizer visualizer, WorkItem workItem ) :  this ()

 4

visualize_embedding函数 visualizer_自定义_29

visualize_embedding函数 visualizer_初始化_30


visualize_embedding函数 visualizer_Software_31

{

 5

visualize_embedding函数 visualizer_初始化_32

    this.visualizer  = visualizer;

 6

visualize_embedding函数 visualizer_初始化_32

    this.cabWorkItem = visualizer.CabRootWorkItem;

 7

visualize_embedding函数 visualizer_初始化_32

    this.thisWorkItem = workItem;

 8

visualize_embedding函数 visualizer_初始化_32

    Monitor m = new Monitor();

 9

visualize_embedding函数 visualizer_初始化_32


10

visualize_embedding函数 visualizer_初始化_32

    this.cabWorkItem.State[ "ListViewMonitor" ] = m.ListViewMonitor;

11

visualize_embedding函数 visualizer_初始化_32

    workItemTree.Nodes.Clear();

12

visualize_embedding函数 visualizer_初始化_32


13

visualize_embedding函数 visualizer_初始化_32

    AddRootWorkItem();

14

visualize_embedding函数 visualizer_自定义_93

visualize_embedding函数 visualizer_初始化_94

    workItem.Workspaces[ "MainWorkspace" ].Show( m, new TabSmartPartInfo 

visualize_embedding函数 visualizer_Software_31

{ ActivateTab = true, Title = "Monitor", Position = TabPosition.Beginning } );

15

visualize_embedding函数 visualizer_自定义_93

visualize_embedding函数 visualizer_初始化_94

    workItem.Workspaces[ "MainWorkspace" ].Show( new About(),   new TabSmartPartInfo 

visualize_embedding函数 visualizer_Software_31

{ Title = "About", Position = TabPosition.End, ActivateTab = false } );

16

visualize_embedding函数 visualizer_自定义_93

visualize_embedding函数 visualizer_初始化_94

    workItem.Workspaces[ "MainWorkspace" ].Show( this,  new TabSmartPartInfo 

visualize_embedding函数 visualizer_Software_31

{ ActivateTab = true, Title = "WorkItem Visualization", Position = TabPosition.Beginning } );

17

visualize_embedding函数 visualizer_Software_34

}

最后三行,我们看到,自定义的 Visualizer 中通过传入的 Root WorkItem 将可显示的监控界面注入到 SCSF 中的 VisualizerForm 中,通过的就是 "MainWorkspace" 名字建立起来的联系。

【FLYabroad】 SCSF 通过模板方法模式结合 ObjectBuilder 提供的依赖注入为我们提供了插件式的 Visualizer 开发接口。SCSF 为我们创建了 Visualizer 主窗体(VisualizerForm), 并通过依赖注入方式将 SCSF 应用的当前 RootWorkItem 实例传入自定义 Visualizer 插件,因此可以在自定义的 Visualizer 中获得我们需要的主应用(并监控应用)的 Workspaces,SmartParts,Services,子 WorkItems,Commands 等用于监控。这也侧面反映了依赖注入的实用价值。