- 问题
你想访问一个WorkItem(工作项)中的组件,但是这个WorkItem不在根结点的WorkItem下,它存在于WorkItem层次结构的其他位置,同时这个结构可能位于其他模块中。
例如:银行客户端参考项目中的基本帐户模块通常包含存款单业务组件,这些组件的实例是特定于某个客户而言的,例如银行职员进行存款单业务的时候使用一个View(视图)来显示当前客户的信息,由于这个职员可以同时为多个客户提供服务,基本帐户模块必须对于每一个客户创建不同的组件实例。
在参考实现中,客户WorkItem已经通过银行系统模块被声明和创建,这就意味基本帐户模块必须添加存款单业务组件到整个WorkItem层次结构中的这个WorkItem下。以下插图显示了工作项层次结构的关系:
Figure 1 Basic Accounts module accessing component in Branch Systems
这个问题概括为,当一个工作项状态发生更改时(例如WorkItem被创建),你需要在另一个的工作项中添加或移除相关组件。
- 解决方案
在工作项状态发生特定的更改时发布事件,将此工作项的引用传递为事件参数。工作项能够发布事件以及传递自身的引用,这样工作项就实现了发布标识。
在分离的模块或工作项中订阅事件,然后在事件处理程序中,使用传事件参数中的工作项引用来访问工作项。
- 职责
工作项发布自己的标识的同时,将它名下的所有内容展现给应用程序的其他部分(任何能够订阅该事件的组件)。
- 示例
银行客户端参考项目中实现了在银行系统工作项层次结构下提供基本帐户模块访问客户工作项的模式。
BranchSystems.Module的ModuleController通过GetOrCreateEntryWorkItem方法创建了一个新的ControlledWorkItem,在它创建工作项之后,它调用OnCustomerWorkItemCreated引发一个CustomerWorkItemCreated的事件。
2 public event EventHandler<EventArgs<WorkItem>> CustomerWorkItemCreated;
3
4 private WorkItem GetOrCreateEntryWorkItem(QueueEntry entry)
5 {
6 string workItemId = entry.QueueEntryID;
7 ControlledWorkItem<CustomerWorkItemController> entryWorkItem = null;
8 if (WorkItem.WorkItems.Contains(workItemId))
9 {
10 entryWorkItem =
11 WorkItem.WorkItems.Get<ControlledWorkItem<CustomerWorkItemController>>
12 (workItemId);
13 }
14 else
15 {
16 entryWorkItem =
17 WorkItem.WorkItems.AddNew<ControlledWorkItem<CustomerWorkItemController>>
18 (workItemId);
19 entryWorkItem.Controller.Run(entry, BranchSystemsWorkspace);
20 OnCustomerWorkItemCreated(entryWorkItem);
21 }
22 return entryWorkItem;
23 }
BasicAccounts.Module中的ModuleController订阅了CustomerWorkItemCreated 事件,在事件处理程序中,它通过事件参数获得了客户的ControlledWorkItem的引用并且添加动作到那个工作项下的动作目录中。
2 public void OnCustomerWorkItemCreated(object sender, EventArgs<WorkItem> args)
3 {
4 WorkItem customerWorkItem = args.Data;
5 customerWorkItem.Items.AddNew<ModuleActions>();
6 ActionCatalog.Execute(ActionNames.ShowPurchaseCDCommand, customerWorkItem, this, null);
7 }
- 更多信息
这个模式使用了Composite UI Application Block的事件发布和订阅模式。