SCSF. Chapter 3. C. WorkItem Details

The main purpose of a WorkItem today is to facilitate 促进 loose coupling by holding certain classes of objects in well-known locations so that other objects can find the resources that they need to do their jobs. To accomplish this, the WorkItem class contains a number of collections, as shown in Table 3-1. All of them are strongly typed except Items, which exists to hold anything not served by a strongly typed collection.

今天workItem的主要目的是通过把中心类放在资源可以获得的地方来促进松耦合。为了完成这点,workItem类包含一些集合展示在3-1表中。除了items其他都是强类型,而items为了保存不是强类型的集合。

Table 3-1. Collections of the WorkItem Class
Property NameDescriptionSearches Parent
Commands Command objects, used for tying .NET events from user interface objects such as menus to business logic methods (see Chapter 5). Yes
EventTopics EventTopic objects, used in conjunction with CAB's loosely coupled publish-and-subscribe event system (see Chapter 6). Yes
Items All objects contained in this WorkItem that do not belong in any of the other collections, which are strongly typed. Web service proxies are a good example of the sort of thing that you often find here, as are WorkItem controllers (see section D of this lesson). No
Services CAB services (see Chapter 2). Yes
Smart Parts Smart Parts, which are objects with the SmartPart attribute applied to them, also known as views (see Chapter 4). No
State State collection associated with this WorkItem. No
UIExtensionSites UIExtensionSite objects, used for negotiating the content of shared user interface items such as menus and toolbars (see Chapter 5). Yes
WorkItems Child WorkItems that belong to this WorkItem. No
Workspaces Workspace objects, which are frames used for visual display of views (see Chapter 4). Yes

Objects are created and placed into the collections of a WorkItem in various ways. Sometimes this happens because of declarative 声明的 attributes that are placed onto a class or a method. For example, the following code appears in the ShellForm class generated by the SCSF Wizard:

对象通过各种各样的方式被创建并放到workItem的集合中。有时是通过声明在方法和类上面的特征。例如,下面代码出现在ShellForm类中通过SCSF向导产生。

[EventSubscription(EventTopicNames.StatusUpdate,
   ThreadOption.UserInterface)]

public void StatusUpdateHandler(object sender, EventArgs<string> e)
{...}

The EventSubscription attribute, when processed by the CAB framework, tells the framework to find the EventTopic object whose name is StatusUpdate in the WorkItem causing the load, creating it if necessary, and to add this particular subscription to it. That EventTopic is created and added to the WorkItem collection the first time this attribute is encountered 遇到 by the CAB framework processing.

EventSubscription特征,当被CAB框架处理时,告诉框架去寻找名为StatusUpdate的EventTopic对象,在这个workItem中产生了加载,创建(因为前面说了,也有可能不创建),和把指定的订阅添加到其中。CAB矿建进程第一遇到这个特征的时候就会创建EventTopic并把它添加到workItem集合中。

Other types of objects are added to WorkItems transparently 显然的 when the CAB object builder creates them. In the ShellForm created by the SCSF, the object builder notes when it is creating the shell form that some of the child controls on the main form are Workspaces and not just plain 简单的 windows. After creating them, the object builder places them into the root work item's Workspaces collection.

很明显当CAB对象创建其他类型时,他们就会被加到workItems中。在SCSF创建的ShellForm中,Object builder意识到当他们创建Shell form的时候,那些子control不是简单的窗口,而是workspaces。在创建完成后,object builder把他们放到root work item的workspaces集合中。

In other cases, objects are added to a WorkItem collection in response to explicit 明确的 method calls. For example, in Chapter 2, we saw that services are often added to WorkItems in this manner 方式. In section D of this chapter, you see how child WorkItems are added this way, and in Chapter 4, you see how Smart Parts are added in this way. Most often it's done by calling the AddNew< > method on the specific collection to which we want to add the new object. This tells the WorkItem to create the object, perform CAB processing on it, such as dependency injection, and return a reference to the newly created object. Alternatively, sometimes you choose a two-step creation process by creating the object separately with the new() operator and then calling Add<> to place it into the WorkItem.

在其他情况下,对象被添加到workItem集合中以响应明确的方法调用。例如,在第二章,我们看到服务服务经常通过这种方法添加到workItem中。在章节D中,你会看到子workItem如何通过此方法被添加,在章节4中,你会看到smart Part如何被这样添加。大部分情况是通过调用AddNew<>方法来指定我们像把新对象放到哪个集合中。这方法告诉workItem创建对象,执行CAB处理,就像依赖注入一样,然后返回一个新对象的引用。作为一种选择,有时你选择两部创建过程来new()对象,然后通过add<>方法来添加。

Occasionally 偶尔, an object is added to a WorkItem collection through a method call that's not quite as obvious as AddNew<>. For example, the call to UIExtensionSites.RegisterSite, which registers a particular user interface item, such as a menu for extension by other parts of the applications, also creates a new UIExtensionSite object in the WorkItem. (This technique is discussed in Chapter 5.)

偶尔,workitem通过一个不像AddNew<>这么明显的方法来把对象添加到workitem集合中。例如,UIExtensionSites.RegisterSite的调用,注册了一个指定的用户接口项,就像是程序其他部分的扩展菜单,同时也创建了一个新的UIExtensionSite对象在wokitem中。

To fetch an item from a WorkItem collection to use it, you usually use the Get method. When using the Services collection, as you saw in the preceding lesson, you specify the interface for which you want the implementing service, thus:

为了从workitem集合中获取一个将要使用的对象,你通常使用Get方法。当使用服务集合,就像你在前一课看到的,你通过指定接口来获得你想要的服务引用,就像这样:

private void AuthenticateUser()
{
   // Fetch the authentication service from the root work item,
   // and call the method to make it authenticate the user.
   IAuthenticationService auth =
        rootWorkItem.Services.Get<IAuthenticationService>(true);
   auth.Authenticate();
}

The objects in the other collections are designated 指定 by string names. You fetch the desired item by indexing the collection with the string name, thus:

其他集合中的对象通过string名来指定。你通过索引器名称来获取对象,就像这样:

// User clicked this button. Look at event topic and
// fire it programmatically.
private void toolStripButton3_Click(object sender, EventArgs e)
{
    EventTopic et =
         _rootWorkItem.EventTopics[EventTopicNames.StatusUpdate] ;
    if (et != null)
    {
        et.Fire(this, new EventArgs<string>("Fired programmatically"),
            _rootWorkItem, PublicationScope.Global );
    }
}

As we've seen, WorkItems in a CAB application are arranged in a hierarchical 分层的 chain. Sometimes a requested object in a collection is present at a higher level than the code making the request. For example, consider the EventTopics collection. The StatusUpdate event, owned by the shell form and used to update the status bar, can reasonably 合理的 be fired from any object anywhere, which is why it's implemented with a loosely coupled CAB event and some tightly coupled technique such as a global variable. An object that has access to a child WorkItem two levels below the root could very reasonably want to fire this event, for which it needs access to the EventTopic.

就像我们看到的,WorkItems在CAB程序中被安放在一个分层的链表中。有时被请求的对象比请求对象展示在更高的层级中。例如,考虑EventTopic集合,StatusUpdate事件,被shell form所拥有并被用来更新状态栏,可以合理的被其他对象在任何时候触发。这就是为什么像一个全局属性一样通过松耦合CAB事件和某些紧耦合技术所实现。一个比root低两层的workitem中的对象想要触发这个事件,他需要访问EventTopic。

Rather than force the requesting object to iterate up the WorkItem chain until it reaches the top, some of the collections in the WorkItem do this automatically. If an object asks WorkItem 4 for the EventTopic named StatusUpdate (which lives in the root), it isn't found there, but the request is automatically sent upward to its parent (WorkItem 2). It isn't found there either, so the request is automatically sent up to WorkItem 2's parent, which is the root WorkItem. In this collection, it is found and returned to the requesting object. This process happens automatically, and the requesting object isn't aware of it.

 不是强迫请求的对象迭代WorkItem chain直到到达顶端,而是让workItem中的某些集合自动完成这件事情。如果一个对象向workItem 4 请求名称为StatusUpdate的EventTopic(存在于root中),这里找不到,但是请求会自动向上传递到父workItem 2。如果还是找不到,请求就被自动传递到workItem 2的父亲,就是root workItem。在这个集合中,它被找到并被传递给请求的对象。这个过程是自动发生的,而且请求对象并没有意识到这点。

For other collections, searching up the WorkItem chain would not make sense. Consider the collection WorkItems, which really means "child WorkItems." If WorkItem 2 in the preceding 之前的 example wants to iterate through its children, it wants to find only WorkItems 3 and 4. It certainly doesn't want to find its siblings (WorkItem 1) or its ancestors (the root WorkItem). Therefore, some collections in a WorkItem search the parent chain and others do not. The "Searches Parent" column in Table 3-1 indicates 表明 which collections search upward through the chain and which don't.

对于其他集合,向上查找workItem链是没有意义的。考虑一下WorkItems集合,实际上是Child WorkItems(相对于root workItem而言)如果WorkItem 2在之前的例子中想在它的子中迭代,它想找到workItem 3和 4。它当然不想找到他的兄弟(workitem 3)或者它的祖先(root workitem)因此,某些workItem中的集合查找父链而其他的则不查找。表3-1中的“Searches Parent”栏表明了哪些集合会向上查找,而哪些则不会。

One of the things that people like to do with any sort of container is to throw it away with all its contents in one neat operation (a kitchen trash bag springs to mind here). The WorkItem class provides this capability 能力 by implementing the IDisposable interface. If you call Dispose on a WorkItem, it iterates through all its collections and calls Dispose on every item that supports that interface. In the CabApplication class startup code, for example, the Run method calls Dispose on the root WorkItem to clean it up as the application is terminating终结. Thus:

有一种操作是大家想要做的,那就是把一个容器以及它所有的内容全部抛弃(这里我想到了厨房垃圾袋)。WorkItem 类提供了这种能力通过实现IDisposable接口。如果你调用workItem的Dispose,它将会迭代它的所有集合并且调用支持Dispose接口的所有项目。在CabApplication类的启动代码中,例如,Run方法调用了Dispose方法在root workItem中来清空root WorkItem当程序终结的时候。像这样:

// CabApplication class startup method

public void Run()
{
   < other initialization stuff... >

   // This method starts the message loop that runs the Windows Forms
   // application. It doesn't return until the app starts shutting
   // down.

   Start();

   // When this method returns, the app is shutting down. Dispose of
   // the root WorkItem, which disposes of all of its contents,
   // including any child WorkItems (and their contents, etc.).

   rootWorkItem.Dispose();

   // Dispose of the Visualizer too, while we're at it, because it
   // doesn't belong to any WorkItem.
   if (visualizer != null)
         visualizer.Dispose();
}
posted @ 2017-02-15 17:38  plovjet  阅读(125)  评论(0)    收藏  举报