您的位置:首页 > 移动开发

Composite UI Application Block学习笔记之一

2008-01-22 22:38 706 查看
Composite UI Application Block 学习笔记

1. 概念(Concept)

1.1. SmartParts

SmartParts provide the visual elements in your applications. These visual elements can be entirely independent of the application in which they are hosted, which allows them to be developed independently as well.
Extension
A SmartPart is built by laying out .NET form components and making a unit of interaction that can fulfill a segment of the use case.

1.2. Workspace

A Workspace is the container and manager for a SmartPart. It can control how the SmartPart is displayed or hidden and how it is laid out. You can create and use the following types of Workspaces:

1.3. WorkItems

图 1‑1 主要对象和模式
A WorkItem is a run-time container of components that are collaborating to fulfill a use case. It contains the following code and classes:
1) Start-up (or initialization) code that initializes the use case
2) State that is shared by components collaborating in the use case
3) Controller classes that act on the state and other resources
4) View classes that interact with their controllers and reference state
5) Tear-down code
Extension
A WorkItem is a unit of work that helps to complete a use case. In most cases, there are five components which compose a WorkItem. These are the visual aspect, the business logic controller, the business entities (customer, account, and so on), services, and state.
During its lifetime, a WorkItem drives the use case by showing or hiding appropriate views. A WorkItem can be composed of other nested WorkItems, each of which can have its own state. This state is analogous to ASP.NET session state.
You can use special persistence techniques to save WorkItems and then restore them later.
WorkItems encapsulate object collaborations for a specific use case, typically using the Model-View-Controller(MVC) pattern. The WorkItem supports the MVC pattern through the following:
1) Model. This is represented by a WorkItem state.
2) View. WorkItems may contain one or more views.
3) Controller. Each view has associated controllers that expose object interfaces for tightly bound interactions and loosely coupled interfaces in the form of commands, events, and subscriptions.

图 1‑2 WorkItem 结构+模式
Note
a WorkItem is a container.

1.4. Infrastructure Services

The Composite UI Application Block includes a set of basic infrastructure services that you can use in your applications. You can also build your own services that provide infrastructure capabilities specific to your applications.
1) Catalog Reader service
2) Module Loader service (模块加载)
3) Authentication service (权限认证)
4) State Persistence service (状态持久)

1.5. Modules

Modules are composed of a set of services,WorkItems,SmartParts, controllers, business entities, and the Module Initialization class, which is used for initializing and running the module's WorkItems.

1.6. Module Services

Module services are objects that you can register once by using the Service attribute, and then reference from any other component from within any WorkItem.

1.7. State

1) A WorkItem contains state, which is a loosely typed collection of objects shared by the components collaborating in the use case. State can be persisted by calling the Load and Save methods on WorkItem.
2) State can be persisted to any storage medium by using an infrastructure service that implements IStatePersistenceService. There are two built in implementations of this service: FileStatePersistenceService, which will persist the WorkItem to a file in the same directory as the executable and IsolatedStorageStatePersistenceService, which will persist the WorkItem to a file in Isolated Storage.

1.8. Controllers

The controllers have the same role that they have in the MVC pattern. They are there to implement the business logic behind the view.
Extension
The Controller base class provides the functionality to access the WorkItem that instantiates the SmartPart and this controller. The Controller base class also provides access to the current state associated with the WorkItem.

1.9. Service Agents

Service agents are components that are used to interact with any external back-end services.

1.10. EventBroker

Components that need to publish or receive notifications use events to perform these tasks. The Composite UI Application Block (CAB) contains the EventBroker feature, which helps you to implement a multicast event scheme (that is, a scheme where zero or more event publications work with zero or more event subscriptions).

2. dependency assemblies依赖组件

The assemblies that you use in a typical CAB implementation are:
1) Microsoft.Practices.CompositeUI.WinForms.dll
2) Microsoft.Practices.CompositeUI.dll
3) Microsoft.Practices.ObjectBuilder.dll

3. Hard Code

3.1. ModuleInit

The class in a module assembly that inherits from ModuleInit is constructed when the CAB is initialized, and its Load method is executed accordingly. It is a mechanism used to initialize a module and all of its segments.
If you want to programmatically add services to the module, override the AddServices method of the ModuleInit class.
If you want to display the user interface or perform custom logic on startup, override the
Load method of the ModuleInit class. These methods are not mandatory.

3.2. ProfileCatalog.xml

The Composite UI Application Block supports the customization of an application by using solution profiles in a catalog. A solution profile is a list of modules that should be loaded into an application.
Because you have created a module and you want to use it in your application, you must define it in the ProfileCatalog.xml. This allows the module loader to load the module.
Example
<?xml version="1.0" encoding="utf-8" ?>
<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile" >
[b]<Modules>

<ModuleInfo AssemblyFile="GPSModule.dll"/>
</Modules>
</SolutionProfile>[/b]

3.3. Creating the Program and Root WorkItem

[STAThread]
static void Main()
{
new Program().Run();
}
Call the Run method on the class. The class implements FormShellApplication<WorkItem, MainForm> and you pass it the type of work item to use and the form to use as the shell.
Calling Run will load the ProfileCatalog.xml file and determine which modules it needs to load. After it retrieves the list of modules, it will begin loading them and initializing them. If any of the modules contain a ModuleInit class, it will construct the class and call the appropriate Load and/or AddServices methods.

4. practice

4.1. WorkItems

A WorkItem is a unit of work that helps to complete a use case. In most cases, there are five components which compose a WorkItem. These are the visual aspect, the business logic controller, the business entities (customer, account, and so on), services, and state.
During its lifetime, a WorkItem drives the use case by showing or hiding appropriate views. A WorkItem can be composed of other nested WorkItems, each of which can have its own state. This state is analogous to ASP.NET session state.
You can use special persistence techniques to save WorkItems and then restore them later.
Extension
There are a number of ways to communicate information between WorkItems and their peer components. One way to achieve this is to store a common state between the WorkItem and its views.
The WorkItem base class holds a property named State that allows you to store a key and value pair. WorkItems have a parent/child relationship; therefore, you can share state between multiple child WorkItems by exposing the state element via a public property.
When storing objects into the State collection on the WorkItem, every one of its views that places the [State] attribute upon a public property will have the object state injected into it at runtime. You can provide a key with the attribute to specify which item in the state will be injected, or if you omit the key, the first object matching the type will be used. This means that we can effectively use the state across all our views without needing to expose a public property within the parent work item.
Example
[State]
public Customer Customer
{
set { customer = value; }
}

4.1.1. Basic WorkItem

4.1.2. Nested WorkItems

5. Attribute

5.1. Service attribute

Service attribute above a class. This attribute is used to register the class as service for the current module. That way, the CAB can easily retrieve the implementations of the services and use them where necessary. You are establishing the ServiceType as the type of your IGPSService interface, which allows you to easily change the implementation without affecting any other code that may need to refer to this service.
Example
public interface IGPSService
{
int GetLatitude();
int GetLongitude();
}
[Service(typeof(IGPSService))]
public class GPSService : IGPSService
{
public int GetLatitude()
{
return 42;
}
public int GetLongitude()
{
return 125;
}
}
The second service introduces a feature called On Demand Services. You use On Demand Services to specify that a service will not be instantiated until it is actually requested for use. To use On Demand Services, add the AddOnDemand attribute, and set it to true.
Example
public interface IDistanceCalculatorService
{
int ComputeDistance(int latitude, int longitude);
}
[Service(typeof(IDistanceCalculatorService), AddOnDemand = true)]
public class DistanceCalculatorService : IDistanceCalculatorService
{
public DistanceCalculatorService()
{
MessageBox.Show("This is DistanceCalculatorService being constructed for the first time. Subsequent calls to the service will not require construction.", "Service constructed", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
public int ComputeDistance(int latitude, int longitude)
{
return 1234;
}
}

5.2. ServiceDependency attribute

private IGPSService gpsService;
[ServiceDependency]
public IGPSService GPS
{
set { gpsService = value; }
}
This code tells the CAB that this class has a dependency on the IGPSService. You have not initialized a new service. You want to use the service that has already been created and stored.
The CAB uses Inversion of Control (IOC) or Dependency Injection to accomplish this task. When you place the [ServiceDependency] attribute on the member property, it will automatically initialize it with the correct service at run time when the view is added to the WorkItem.

5.3. SmartParts attribute

[SmartPart]
public partial class CustomerQueueView : UserControl

This attribute marks the control as a SmartPart. This is required to support the inversion of control functionality, which will automatically associate service dependencies, controllers, and so on.

5.4. InjectionConstructor

[InjectionConstructor]
public BankTellerModuleInit([ServiceDependency] WorkItem workItem)
{
this.workItem = workItem;
}


5.5. CommandHandler

5.6. EventPublication

Example
[EventPublication("topic://BankShell/statusupdate", PublicationScope.Global)]
public event EventHandler<DataEventArgs<string>> UpdateStatusTextEvent;
protected virtual void OnStatusTextUpdate(string newText)
{
if (UpdateStatusTextEvent != null)
{
UpdateStatusTextEvent(this, new DataEventArgs<string>(newText));
}
}
1) Notes:
This attribute uses two parameters: the event topic and the PublicationScope. The event topic is a string that identifies the event, for example "topic://BankShell/statusupdate". It is recommended that you use a URI syntax to allow for hierarchical naming conventions. For example, topic://UpdatesAvailable/New and topic://UpdatesAvailable/Deleted. The PublicationScope specifies what components will be able to receive the event.
2) PublicationScope settings are:
A、Global (default) indicates that the event is available in any WorkItem.
B、WorkItem indicates the event should be sent only to objects contained within the same WorkItem as the publishing object
C、Descendants indicates the event should be sent to objects contained within the same WorkItem as the publishing object and recursively to all child WorkItems and their contents.

5.7. EventSubscription

Example
[EventSubscription("topic://BankShell/statusupdate",
Thread = ThreadOption.UserInterface)]
public void OnStatusUpdate(object sender, DataEventArgs<string> e)
{
toolStripStatusLabel1.Text = e.Data;
}
Warning:
Any code can use the EventTopic class to register a subscriber, and subscriber code can potentially be malicious code running at a lower trust level than the application code. If your application accepts delegates from untrusted sources, you should use security permissions to restrict the code access permissions available to delegate methods.
ThreadOption settings are:
A、Publisher (default), which indicates that the handler is called synchronously on the publisher's thread.
B、Background, which indicates that the handler should be called in a separate background thread.
C、UserInterface, which indicates that the handler is called on the user interface thread; therefore, it is safe for it to modify user interface elements.

6. Interface

6.1. IStatePersistenceService

FileStatePersistenceServicethe default implementation of this interface. StreamStatePersistenceService
The FileStatePersistenceService implementation inherits from StreamStatePersistenceService, and uses the BinaryFormat serializer to store state in binary files. It contains members to save, load, and remove state files, and uses the WorkItem's Id (a GUID) to identify the file. The service can receive the base path used to store state in the constructor.
There is also a similar service named IsolatedStorageStatePersistenceService that you can use to store items in isolated storage.
Applications can use isolated storage to save data in their own isolated portion of the file system, without having to specify a particular path in the file system. Because isolated stores are scoped to particular assemblies, most other managed code will not be able to access your code's data (highly trusted managed code and administration tools can access stores from other assemblies). Unmanaged code can access any isolated stores.
Notes:
A、The base class, StreamStatePersistenceService, implements the IConfigurable interface to permit a cryptography flag to be set through configuration. If this flag is set, the ICryptographyService is used when state is saved and loaded.
B、When the application uses cryptography for state persistence, it uses an entropy value stored in the configuration file. You should make sure that you secure this configuration file, or, alternatively, you should store the entropy value in the registry. To avoid entropy management issues, you could use the machine store without entropy, and then use code access security to validate users and code. For more information about key management and security, see Building Secure Assemblies.

6.2. IConfigurable

7. 编码技巧

7.1. Using Tracing in Your Application

1) 相关代码
private TraceSource traceSource = null;
[TraceSource("BankTellerModule")]
public TraceSource TraceSource
{
get { return traceSource; }
set { traceSource = value; }
}

public override void Load()
{
// TODO: Trace a message
traceSource.TraceInformation("BankTellerModule is starting ...");
// Register workitem so others can create it and use it.
workitemCatalog.RegisterWorkItem<BankTellerWorkItem>();
}
2) 项目设置

图 7‑1 项目设置
3) App.config
<system.diagnostics>
<switches>
<add name="BankTellerModule" value="all" />
</switches>
<sharedListeners>
<add name="console"
type="System.Diagnostics.ConsoleTraceListener"
initializeData="false"/>
</sharedListeners>
<sources>
<source name="BankTellerModule" switchName="BankTellerModule">
<listeners>
<add name="console" />
</listeners>
</source>
</sources>
</system.diagnostics>
This section defines a new ConsoleTraceListener listener within a sharedListeners section, which allows multiple sources to share one listener. You have also defined a switch that you have set to all so that it works for all types of traces. To turn the tracing off, you can set this value to off. Other valid options for this value are error, warning, info and verbose.
4) 设置项目输出

图 7‑2 项目输出
By setting the application output type to Console Application, you displaythe console window so that you can see your trace messages.

Tracing the CAB

The following list shows some of the TraceSources available in the CAB:

Microsoft.Practices.ObjectBuilder: Used by the DependencyInspector.
Microsoft.Practices.CompositeUI: Used by the State service.
Microsoft.Practices.CompositeUI.Configuration: Used by the Configuration service.
Microsoft.Practices.CompositeUI.EventBroker: Used by the EventBroker.
Microsoft.Practices.CompositeUI.Services: Used by the module that is loaded.

NOTE: There are other CAB TraceSources defined in the following namespaces:

Microsoft.Practices.CompositeUI.State
Microsoft.Practices.CompositeUI.Services.WorkItemExtensionService
Microsoft.Practices.CompositeUI.Services.ModuleLoaderService
Microsoft.Practices.CompositeUI.WorkItem
Microsoft.Practices.CompositeUI.EventBroker.EventTopic
Microsoft.Practices.CompositeUI.Commands.Command

In the App.config file, replace the <system.diagnostics> section with the following.
<system.diagnostics>
<switches>
<add name="BankTellerModule" value="all" />
</switches>
<sharedListeners>
<add name="console"
type="System.Diagnostics.ConsoleTraceListener"
initializeData="false"/>
</sharedListeners>
<sources>
<source name="BankTellerModule" switchName="BankTellerModule">
<listeners>
<add name="console" />
</listeners>
</source>

<source name="Microsoft.Practices.ObjectBuilder" switchName="BankTellerModule">
<listeners>
<add name="console" />
</listeners>
</source>
<source name="Microsoft.Practices.CompositeUI" switchName="BankTellerModule">
<listeners>
<add name="console" />
</listeners>
</source>
<source name="Microsoft.Practices.CompositeUI.Configuration" switchName="BankTellerModule">
<listeners>
<add name="console" />
</listeners>
</source>
<source name="Microsoft.Practices.CompositeUI.EventBroker" switchName="BankTellerModule">
<listeners>
<add name="console" />
</listeners>
</source>
<source name="Microsoft.Practices.CompositeUI.Services" switchName="BankTellerModule">
<listeners>
<add name="console" />
</listeners>
</source>
</sources>
</system.diagnostics>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: