当前位置: 代码迷 >> 综合 >> Composite UI Application Block 学习笔记之二
  详细解决方案

Composite UI Application Block 学习笔记之二

热度:76   发布时间:2024-01-18 06:46:32.0

Composite UI Application Block 学习笔记

1.   重要对象解析

1.1. WorkItem

WorkItem中,有如下的成员变量:

private WorkItem parent;

private ManagedObjectCollection<WorkItem> workItemCollection;

表明在这个设计中,WorkItem支持多级嵌套,我们可以想象一个程序是由众多的WorkItem组成,而这些WorkItem是由一个树形结构组织在一起,就好比VS2005的选项设置一样,如下图所示:

1?1 workitem的树形结构

下面这张图片可能形象一些

1?2 WorkItem的组织结构

RootWorkItem可以说是CAB的根本,在它身上承载了太多的资源,比如Shell’s Workspaces,,各种Service,以及各种UI Extensions。下面简单说说RootWorkItem的创建过程。

CabApplication<TWorkItem>中,导火索是从Run()方法开始,程序代码如下

/// <summary>

           /// Starts the application.

           /// </summary>

           public void Run()

           {

                 RegisterUnhandledExceptionHandler();

                 Builder builder = CreateBuilder();

                 AddBuilderStrategies(builder);

                 CreateRootWorkItem(builder);

                 IVisualizer visualizer = CreateVisualizer();

                 if (visualizer != null)

                      visualizer.Initialize(rootWorkItem, builder);

                 AddRequiredServices();

                 AddConfiguredServices();

                 AddServices();

                 AuthenticateUser();

                 ProcessShellAssembly();

                 rootWorkItem.BuildUp();

                 LoadModules();

                 rootWorkItem.FinishInitialization();

                 rootWorkItem.Run();

                 Start();

                 rootWorkItem.Dispose();

                 if (visualizer != null)

                      visualizer.Dispose();

           }

           }

Run()方法中,首先创建了一个builder对象,然后New了一个RootWorkItem,当然创建过程没有这么简单,它还需要借助ObjectBuilder的力量进行各种依赖注入,所以先通过AddBuilderStrategies加入几个Strategy,这些策略都是对Workitem进行初始化用的,然后通过调用rootWorkItem.BuildUp()完成各种依赖注入。

在这里需要注意的是builder对象在整个运用程序执行期间只有一个实例,为什么这么说呢,我们再看workitem的源代码,

private void InitializeFields()

           {

                 if (builder == null)

                      builder = parent.builder;

                 if (locator == null)

                      locator = new Locator(parent.locator);

                 if (!locator.Contains(typeof(ILifetimeContainer), SearchMode.Local))

                      locator.Add(typeof(ILifetimeContainer), lifetime);

                 ObjectBuiltNotificationPolicy policy = builder.Policies.Get<ObjectBuiltNotificationPolicy>(null, null);

                 if (policy != null)

                 {

                      policy.AddedDelegates[this] = new ObjectBuiltNotificationPolicy.ItemNotification(OnObjectAdded);

                      policy.RemovedDelegates[this] = new ObjectBuiltNotificationPolicy.ItemNotification(OnObjectRemoved);

                 }

                 LocateWorkItem(typeof(WorkItem));

                 LocateWorkItem(GetType());

                 status = WorkItemStatus.Inactive;

           }

可以看出,所有子节点的workitem都是从父节点把一些关键的资源传递下来,其中就有刚才说的builder对象, 哦,单件模式还可以这样实现J

值得关注的另一个焦点应该就是Locator了,Locator本身也支持嵌套,不过不像WorkItem那样到处开枝散叶,它只支持简单的层次结构,如下图所示:

1?3 简单嵌套

也可以通过代码来印证:

public abstract class ReadableLocator : IReadableLocator

      {

           private IReadableLocator parentLocator;

           ……

      }

workitem的初始化代码中可以看出,

if (locator == null)

      locator = new Locator(parent.locator);

workitem对象总是从它的父节点那把Locator给继承了下来,(这里所说的继承实际上只有持有一个引用而已,只是为了说明上的直观性。)这样也就实现了资源的层层查找,这也就是SearchMode 的意义所在了。

       在程序中,如果要取得RootWorkItem,可以用下列代码获取:

context.Locator.Get<WorkItem>(new DependencyResolutionLocatorKey(typeof(WorkItem), null)),为什么可以这样取得,是因为在workitem的初始化代码中做了设定。

private void InitializeFields()

           {

                 ……

LocateWorkItem(typeof(WorkItem));

                 LocateWorkItem(GetType());

……

}

            private void LocateWorkItem(Type workItemType)

           {

                 DependencyResolutionLocatorKey key = new DependencyResolutionLocatorKey(workItemType, null);

                 if (!locator.Contains(key, SearchMode.Local))

                      locator.Add(key, this);

           }

      

1.2. CabApplication

CabApplication对象的众多方法中,最重要的莫过于Run方法了,而在Run方法中,最重要的莫过于RootWorkItem的创建。

/// <summary>

           /// Starts the application.

           /// </summary>

           public void Run()

           {

                 RegisterUnhandledExceptionHandler();

                 Builder builder = CreateBuilder();

                 AddBuilderStrategies(builder);

                 CreateRootWorkItem(builder);

                 IVisualizer visualizer = CreateVisualizer();

                 if (visualizer != null)

                      visualizer.Initialize(rootWorkItem, builder);

                 AddRequiredServices();

                 AddConfiguredServices();

                 AddServices();

                 AuthenticateUser();

                 ProcessShellAssembly();

                 rootWorkItem.BuildUp();

                 LoadModules();

                 rootWorkItem.FinishInitialization();

                 rootWorkItem.Run();

                 Start();

                 rootWorkItem.Dispose();

                 if (visualizer != null)

                      visualizer.Dispose();

           }

           }

首先创建一个Builder对象,在创建builder对象时,需要注意的是加入了若干个Strategy

      private Builder CreateBuilder()

           {

                 Builder builder = new Builder();

                 builder.Strategies.AddNew<EventBrokerStrategy>(BuilderStage.Initialization);

                 builder.Strategies.AddNew<CommandStrategy>(BuilderStage.Initialization);

                 builder.Strategies.Add(new RootWorkItemInitializationStrategy(this.OnRootWorkItemInitialized), BuilderStage.Initialization);

                 builder.Strategies.AddNew<ObjectBuiltNotificationStrategy>(BuilderStage.PostInitialization);

                 builder.Policies.SetDefault<ISingletonPolicy>(new SingletonPolicy(true));

                 builder.Policies.SetDefault<IBuilderTracePolicy>(new BuilderTraceSourcePolicy(new TraceSource("Microsoft.Practices.ObjectBuilder")));

                 builder.Policies.SetDefault<ObjectBuiltNotificationPolicy>(new ObjectBuiltNotificationPolicy());

                 return builder;

           }

很显然,CAB提供的若干个显著特征都包含在这些个Strategy中,我们先来说说RootWorkItemInitializationStrategy,它是专门用于初始化RootWorkItem的,并提供一个回调。(callback

            /// <summary>

           /// See <see cref="BuilderStrategy.BuildUp"/> for more information.

           /// </summary>

           public override object BuildUp(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)

           {

                 WorkItem wi = existing as WorkItem;

                 if (wi != null && wi.Parent == null)

                      callback();

                 return base.BuildUp(context, typeToBuild, existing, idToBuild);

           }

注意这行代码

if (wi != null && wi.Parent == null)

确保只对RootWorkItem起作用。

这里提供的回调函数则为OnRootWorkItemInitialized,不过在这里只是一个虚方法,

            /// <summary>

           /// May be overridden in a derived class to perform work after the root <see cref="WorkItem"/> has been fully initialized.

           /// </summary>

           protected virtual void OnRootWorkItemInitialized()

           {

           }

它的作用就是被子类重载,比如在CabShellApplication中,

            /// <summary>

           /// Creates the shell.

           /// </summary>

           protected sealed override void OnRootWorkItemInitialized()

           {

                 BeforeShellCreated();

                 shell = RootWorkItem.Items.AddNew<TShell>();

                 AfterShellCreated();

           }

用来建立一个Shell,也就是我们赖以生存的主窗体。

1.3. Module

WorkItem通常位于Module中,在一个Module加载的时候,首先取得Root WorkItem的一个引用,刚才我们看到,Root WorkItem是被Application Shell创建(在程序运行之初),Shell然后加载Module,接着把其中的所有workitem都加入到RootWorkitem旗下。最终组成一支浩浩荡荡的WorkItem大军。

我们来看一个示例:

public class BankTellerModuleInit : ModuleInit

      {

           private WorkItem workItem;

          

           [InjectionConstructor]

           public BankTellerModuleInit([ServiceDependency] WorkItem workItem)

           {

                 this.workItem = workItem;

           }

           public override void Load()

           {

                 AddCustomerMenuItem();

                 //Retrieve well known workspaces

                 IWorkspace sideBarWorkspace = workItem.Workspaces[WorkspacesConstants.SHELL_SIDEBAR];

                 IWorkspace contentWorkspace = workItem.Workspaces[WorkspacesConstants.SHELL_CONTENT];

                 BankTellerWorkItem bankTellerWorkItem = workItem.WorkItems.AddNew<BankTellerWorkItem>();

                 bankTellerWorkItem.Show(sideBarWorkspace, contentWorkspace);

           }

其中

[InjectionConstructor]

           public BankTellerModuleInit([ServiceDependency] WorkItem workItem)

           {

                 this.workItem = workItem;

           }

就是获取一个RootWorkItem

然后在Load()方法中,则是完成把workitem加入到RootWorkItem的工作:

BankTellerWorkItem bankTellerWorkItem = workItem.WorkItems.AddNew<BankTellerWorkItem>();

2.   重要机制解析

2.1. 用户验证

验证方法存在于CabApplicationRun方法中,

/// <summary>

           /// Starts the application.

           /// </summary>

           public void Run()

           {

                 ……

AddServices();

                 AuthenticateUser();

……

           }

           private void AuthenticateUser()

           {

                 IAuthenticationService auth = rootWorkItem.Services.Get<IAuthenticationService>();

                 if (auth != null)

                      auth.Authenticate();

           }

从上面可以看出,实际上只要我们创建一个实现了IAuthenticationService接口的类,然后加入到服务集合中,就能顺顺当当的调用我们自己的实现了。

范例代码如下所示:

protected override void AddServices()

           {

                 base.AddServices();

                 base.RootWorkItem.Services.AddNew<MobileCabAuthenticationService, IAuthenticationService>();

                 ……

           }

 
  相关解决方案