7. 构建 RootWorkItem (rootWorkItem.BuildUp()) RootWorkItem 通过 builder.BuildUp(locator, type, temporaryID, this, policies) 方法使用 ObjectBuilder 进行构建,前面介绍过 CabApplication 在 CreaterBuilder() 中注册了构建策略 RootWorkItemInitializationStrategy: builder.Strategies.Add(new RootWorkItemInitializationStrategy(this.OnRootWorkItemInitialized), BuilderStage.Initialization),该语句表明在创建 RootWorkItem 时 ObjectBuilder 会执行该策略并调用本类(CabApplication 或者重载的子类)的 OnRootWorkItemInitialized 方法:protected virtual void OnRootWorkItemInitialized()。CabShellApplication (CabApplication 的子类) 重写了该方法:

Code
1 protected sealed override void OnRootWorkItemInitialized()
2 {
3 BeforeShellCreated();
4 shell = RootWorkItem.Items.AddNew<TShell>();
5 AfterShellCreated();
6 }
其中 RootWorkItem.Items.AddNew<TShell>() 语句创建了新的 TShell 主窗体对象(通过 ObjectBuilder 构建)并加入到 RootWorkItem 的 Items 集合中。
8. 通过配置加载模块(LoadModules())RootWorkItem 构建完成后,SCSF 会根据 IModuleEnumerator 服务来枚举可以加载的模块(确定需要加载哪些模块),SCSF 中提供了两个 IModuleEnumerator 服务:FileCatalogModuleEnumerator(在配置文件中指明要加载哪些模块,默认的配置文件是 ProfileCatalog.xml )和 ReflectionModuleEnumerator(利用反射和 ModuleAttribute 来确定需要加载哪些模块)。同时 SCSF 的Package Guidance 为我们提供了一个 XmlStreamDependentModuleEnumerator ,用于从 Xml Stream 中确定需要加载哪些模块,这个可以用在通过 Web Service 将服务器上的配置发送到客户端的情况。
典型的配置文件示例 ProfileCatalog.xml :

Code
<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile/2.0%22>
<Section Name="Infrastructure">
<Modules>
<ModuleInfo AssemblyFile="GlobalBank.Support.Module.dll" />
<ModuleInfo AssemblyFile="GlobalBank.Infrastructure.Module.dll" />
</Modules>
</Section>
<Section Name="BranchSystems">
<Dependencies>
<Dependency Name="Infrastructure" />
</Dependencies>
<Modules>
<ModuleInfo AssemblyFile="GlobalBank.BranchSystems.Layout.dll" Name="BranchSystems.Layout"/>
<ModuleInfo AssemblyFile="GlobalBank.BranchSystems.Module.dll">
<Dependencies>
<Dependency Name="BranchSystems.Layout" />
</Dependencies>
<Roles>
<Role Allow="Greeter"/>
<Role Allow="Officer"/>
<Role Allow="BranchManager"/>
</Roles>
</ModuleInfo>
</Modules>
</Section>
<Section Name="LinesOfBusiness">
<Dependencies>
<Dependency Name="Infrastructure" />
<Dependency Name="BranchSystems" />
</Dependencies>
<Modules>
<ModuleInfo AssemblyFile="GlobalBank.BasicAccounts.Module.dll">
<Roles>
<Role Allow="Officer"/>
<Role Allow="BranchManager"/>
</Roles>
</ModuleInfo>
<ModuleInfo AssemblyFile="GlobalBank.CreditCardAccounts.Module.dll">
<Roles>
<Role Allow="Officer"/>
<Role Allow="BranchManager"/>
</Roles>
</ModuleInfo>
</Modules>
</Section>
</SolutionProfile>
确定要加载那些模块后,就会执行上面 “6. 处理 Shell 程序集”中的过程,利用注册的 IModuleLoaderService 加载模块。SCSF 规定每个 Module 程序集都有一个继承自 ModuleInit 的子类,IModuleLoaderService 会在加载完该 Module 后自动调用其 void Load() 方法,这里是 SCSF 为我们通过的接入点,我们应该在 void Load() 方法中初始化本模块。具体应该初始化什么以后介绍。
9. 完成对 RootWorkItem 的创建(rootWorkItem.FinishInitialization()) 主要是处理 workItem 扩展(以后介绍),并触发创建完成事件:

Code
1 protected internal void FinishInitialization()
2 {
3 IWorkItemExtensionService extensionsService = Services.Get<IWorkItemExtensionService>();
4 if (extensionsService != null)
5 extensionsService.InitializeExtensions(this);
6
7 OnInitialized();
8 }
9
同时 WorkItem 的 public void InitializeWorkItem() 是一个注入方法,有[InjectionMethod]属性标记,该方法执行时除了执行上面 rootworkItem中的初始化过程外,还会调用 InitializeServices 方法,该方法在 CabApplication 中是空方法,CabApplication 子类可以重写 protected virtual void InitializeServices() 方法,用于在 WorkItem 初始化时加载其他需要的服务。
10. 执行 rootWorkItem 的 run 方法 rootWorkItem.Run();WorkItem 的 Run 方法直接调用 protected virtual void OnRunStarted() 方法:

Code
1 public void Run()
2 {
3 OnRunStarted();
4 }
OnRunStarted 方法触发 RunStarted 事件(public event EventHandler RunStarted)

Code
1 protected virtual void OnRunStarted()
2 {
3 if (this.RunStarted != null)
4 {
5 this.RunStarted(this, EventArgs.Empty);
6 }
7
8 if (traceSource != null)
9 traceSource.TraceInformation(String.Format(
10 CultureInfo.CurrentCulture,
11 Properties.Resources.TraceWorkItemRunStarted, ID));
12 }
13
因此我们可以通过注册 RunStarted 事件或者在 WorkItem 子类中重写 OnRunStarted() 虚方法以便在 SCSF 启动过程中执行自己的操作,这是 SCSF 的又一扩展点。
11. 启动应用 Start() CabApplication 中的 Start 是一个抽象方法:protected abstract void Start();
子类 FormShellApplication(public abstract class FormShellApplication<TWorkItem, TShell> : WindowsFormsApplication<TWorkItem, TShell>) 重写了Start :

Code
1 protected override void Start()
2 {
3 Application.Run(Shell);
4 }
很简单,这时主窗体就显示出来了,以后的整个操作就是通过用户交互来触发了。
以上只是简单的介绍了一下 SCSF 的启动流程,还有很多细节后面的文章会接受。