Tuesday, September 4, 2007

Designing and Building a CAB Application

1. Create the shell and the form, and displaying the form
2. creating and loading the module
3. Adding the tabbed workspace to the form and running the module
4. Creating and adding the SmartPart user control to the module, and displaying the results through this SmartPart


Creating the Shell and the Form

1. Application name -> ShellApplication

2. Form1.cs -> ShellForm.cs

3. Add References
Microsoft.Practices.CompositeUI.dll
Microsoft.Practices.CompositeUI.WinForms.dll
Microsoft.Practices.ObjectBuilder.dll
Adding a new WorkItem

4. Add New class named ShellWorkItem.cs
Using Microsoft.Practices.CompositeUI

5. Class should be public and inherit from WorkItem
public class ShellWorkItem : WorkItem
{
}
6. Rename Program.cs to ShellApplication.cs
using Microsoft.Practices.CompositeUI.WinForms;
7. Replace the static class with public and inherit from FormShellApplication
public class ShellApplication : FormShellApplication<ShellWorkItem, ShellForm>
{
}
8. Add the [STAThread] attribute and intiate ShellApplication class and call Run method.
[STAThread]
static void Main()
{
new ShellApplication().Run();
}


Creating and Loading the Module

1. Create a new Class Library named MyModule

2. set Outputpath to ..\ShellApplication\bin\Debug (from project properties build output page)

3. Add reference
Microsoft.Practices.CompositeUI.dll
Microsoft.Practices.CompositeUI.WinForms.dll
Microsoft.Practices.ObjectBuilder.dll
4. Add a class named MyWorkItem.cs. Make it public and derive from WorkItem
using Microsoft.Practices.CompositeUI;
public class MyWorkItem : WorkItem
{
}
5. Add a class named MyModuleInit.cs and make it public and derive from ModuleInit. Add a variable myCatalogService reference the WorkItemTypeCatalogService. so that you can access it to register your WorkItem.
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.Services;
using System.Windows.Forms;

public class MyModuleInit : ModuleInit
{
private IWorkItemTypeCatalogService myCatalogService;
}
6. Add the following public property
[ServiceDependency]
public IWorkItemTypeCatalogService myWorkItemCatalog
{
set { myCatalogService = value; }
}
7. Override the Load method of ModuleInit
public override void Load()
{
base.Load();
myCatalogService.RegisterWorkItem<MyWorkItem>();
}
8. Add a new XML file named ProfileCatalog.xml
<?xml version="1.0" encoding="utf-8" ?>
<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile">
<Modules>
<ModuleInfo AssemblyFile="MyModule.dll" />
</Modules>
</SolutionProfile>
9. select property of ProfileCatalog.xml and change the Copy To Output Directory property to Copy Always


Adding the TabWorkspace

1. Open the ShellForm.cs and drag a SplitContainer control onto the form

(Note: right click the Toolbox, click items.. and then browse and select
Microsoft.Practices.CompositeUI.Winforms.dll)
2. Drag a TabWorkSpace onto the form and drop it onto the left hand panel of the SplitContainer.

3. Right click the TabWorkSpace and click Remove Tab.


Creating and Showing the SmartPart

Create an Interface

1. Add a new Interface named IMyView.cs and make it public
public interface IMyView
{
event EventHandler Load;
string Message { get; set; }
}
Create a SmartPart user control

1. Add a new User Control named MyView.cs

2. Drag a Label control

3. Derive the class Myview from IMyView
public partial class MyView : UserControl, IMyView
4. Right-click IMyView and click Implement Interface.

5. Replace the two throw statements
public string Message
{
get
{
return this.label1.Text;
}
set
{
this.label1.Text = value;
}
}
Create a Presenter

6. Create a new class named MyPresenter.cs and add a variable of type IMyView
public class MyPresenter
{
IMyView view;
7. Create a constructor for the class. The constructor takes a reference to the view, sets it as the view for this presenter, and subscribes to the Load event of the view
public MyPresenter(IMyView view)
{
this.view = view;
view.Load += new EventHandler(view_Load);
}
8. Create an Event handler for the Load event. This sets the Message property of the Label control
void view_Load(object sender, EventArgs e)
{
view.Message = "Hello World from a Module";
}
Reference to the WorkItem

1. Open the MyModuleInit.cs and add a variable parentWorkItem. It reference to the root ShellWorkItem
private WorkItem parentWorkItem;

2. Add a public property to the class. It references the existing WorkItem, and passes back a reference to it.
[ServiceDependency]
public WorkItem ParentWorkItem
{
set { parentWorkItem = value; }
}
3. Modify the Load method
public override void Load()
{
base.Load();
MyWorkItem myWorkItem = parentWorkItem.WorkItems.AddNew<MyWorkItem>();
myWorkItem.Run(parentWorkItem.Workspaces["tabWorkspace1"]);
}

Create and show the view

4. Open the file MyWorkItem.cs
using Microsoft.Practices.CompositeUI.SmartParts;
5. Create a public Run method that accepts as a parameter a reference to the TabWorkspace (IWorkspace will let you change the type of workspace in future)
public void Run(IWorkspace TabWorkspace)
{
}
6. Add statements to the Run method that create a new instance of the MyView class and a new instance of the MyPresenter class. Passing the view instance you just created to the presenter connects them together
IMyView view = this.Items.AddNew<MyView>();
MyPresenter presenter = new MyPresenter(view);
7. Add statements to the Run method that add the new presenter to the current WorkItem and call the Show method of the TabWorkspace to display the view.
this.Items.Add(presenter);
TabWorkspace.Show(view);

Saturday, September 1, 2007

The Endpoint Catalog Application block

Is a simple service that uses a dictionary to store
  1. Endpoints - An endpoint consists of a name and a series of network names appropriate for that endpoint.
  2. Associated credential for each endpoint - A credential consists of two or three String values: a user name, a password, and optinally a logon domain name.
The following XML shows a typical configuration section in an App.config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration?>
...
<Endpoints?>
<EndpointItems?>

<add Name="my-host-name" Address="http://default-host.com/path"
UserName="user-name" Password="password"?>
<NetworkItems?>
<add Name="Internet" Address="http://internet-host.com/path"
UserName="user-name" Password="password" /?>
<add Name="Work" Address="http://work-host.com/path"
UserName="user-name" Password="password" Domain="domain-name" /?>
</NetworkItems?>
</add?>

</EndpointItems?>
</Endpoints?>

</configuration?>


Configuring the Endpoint Catalog Application Block

Define a configuration section for the application block in the application configuration file.
<configSections >
<section name="Endpoints" type="Microsoft.Practices.SmartClient.EndpointCatalog.Configuration.EndpointSection, Microsoft.Practices.SmartClient.EndpointCatalog" />
</configSections>

Creating an Endpoint Catelog Class Instance

Create a new EndpointCatalog and add it to a WorkItem

1. Add a refrence to the Endpoint Catalog Application block to your project and import the namespace
using Microsoft.Practices.SmartClient.EndpointCatalog;
2. If you intend to work with individual credentials, you must also import
using System.Net;
3. Create a new instance of the EndpointCatalogFactory class.

Save the new insatnce of the factory class as an IEndpointCatalogFactory interface type in case you decide to extend the application block later by creating a custom class that implements this interface.
// Specify the section name in the configuration file.
String configName = "Endpoints";
IEndpointCatalogFactory catalogFactory = new EndpointCatalogFactory(configName);
4. Use the CreateCatalog method of the EndpointCatalogFactory, that contains details of all the configured endpoints for the application.
IEndpointCatalog catalog = catalogFactory.CreateCatalog();

5. Add it to the root WorkItem of your application.
myWorkItem.Services.Add(catalog);


Getting an Endpoint Catalog Instance from a WorkItem

There are 3 methods

1. use a [ServiceDependency] attribute on a parameter of your class constructor to accept an injected reference and store it in a class-level variable.

public class MyNewClass
{
private EndpointCatalog catalog;

public MyNewClass([ServiceDependency] EndpointCatalog catalog)
{
this.catalog = catalog;
}
...
}
2. Expose a public property for the EndpointCatalog and have ObjectBuilder set it to the EndpointCatalog instance in the WorkItem.
public class MyNewClass
{
private EndpointCatalog catalog;

[ServiceDependency]
public EndpointCatalog EndpointCatalog
{
get { return this.catalog; }
set { this.catalog = value; }
}
...
}

3. Query the Services collection of the WorkItem directly to obtain a reference to the service you want
public class MyNewClass
{
private EndpointCatalog catalog;

public MyNewClass()
{
this.catalog = myWorkItem.Services.Get<endpointcatalog>();
}
...
}

Listing and Getting Information about Endpoints

Use EndpointExists method to Check whether an endpoint exists in the catalog
Use EndpointCatalog class to get information about an endpoint

// Get the number of endpoints in the catalog.
int endpointCount = catalog.Count;
// Get the address for an endpoint if it exists.
String epName = "MyWebServiceEndpoint";
String epNetworkName = "MyHost";
if (catalog.AddressExistsForEndpoint(epName, epNetworkName))
{
String epAddress = catalog.GetAddressForEndpoint(epName, epNetworkName);
// Get the credentials for this endpoint.
NetworkCredential epCredentials = catalog.GetCredentialForEndpoint(epName, epNetworkName);
String epUsername = epCredentials.UserName;
String epPassword = epCredentials.Password;
String epDomain = epCredentials.Domain;
}

The Disconnected Service Agent Application Block

Which provides management features for executing Web services from occationally connected smart client applications.

The application can maintain a queue of Web service requests when offline and then replay them when a connection to the server application becomes available.

Core Classes
  1. RequestManager class - manages the request queues and uses the services of the RequestDispatcher class to dispatch these requests. It stores the queues of pending and failed requests.
  2. Request class - is a store for a Web service request, including the arguments or parameters required by the Web service method.
  3. ConnectionMonitorAdapter class provides information about the connection used by the request

Request Manager Subsystem

Controls the dispatching of Web service requests. It takes the messages from the queue and dispatches them when the application is online
It allows you to stop and start automatic dispatch, dispatch all pending requests, and dispatch individual requests.
The requests remain in the database until successful submission to remote server or until the request expires or when exceeding the specified number of retries.

You can access the single instance of the RequestManager class through its Instance property and by calling the initialize method with following parameters
  1. The queues for pending and failed requests
  2. A reference to a class that implements the IConnectionMonitor interface
  3. A reference to a class that implements the IRequestDispatcher interface
  4. An instance of the EndPointCatalog class that contains the endpoints to use for the request.

The Request Class Hierarchy

Provide features required to create individual requests to send to a remote Web service. It exposes the properties that define the behavior, parameters, endpoints, and other details for the request.
The Enqueue method add the request to the queue or dispatch it immediately.
It exposes the CallParameters property to contain the arguments for the Web service method.

You can also influence the behavior of a request through the OfflineBehavior class. It specifies the features of the request, such as the expiration, maximum number of retries, relaive importance of request, Tag value.

The OfflineBehavior class exposes two properties that allow you to define callback handlers for its ReturnCallback and ExceptionCallback properties as instances of the CommandCallback class.


The ConnectionMonitorAdapter Class

It exposes information about the underlying connection.
It allow you to handle in your code to get information about changes to the connection state. connectionStatusChange event occurs when the current connection state changes.


Initializing the Request Manager

Assume that the queues use the table names Requests and DeadLetter for pending and failed queues.

1. add referene
Microsoft.Practices.Smartclient.DisconnectedAgent
Microsoft.Practices.Smartclient.EnterpriseLibrary
2. Invoke any of the overloads of the static method Initialize.
RequestManager requestManager = DatabaseRequestManagerIntializer.Initialize();
it using the default database specified in the Data Access application Block configuration

// or

RequestManager requestManager = DatabaseRequestManagerIntializer.Initialize("databaseName");
You can specify a particular data base.

Creating a Simple Request

1. Create a new instance of the Request class and set the properties for this request. you must specify the name of the Web service method exposed by the remote server and the name of the endpoint.
Request req = new Request();
req.MethodName = "DeliveryRouteUpdate";
req.Endpoint = "MyWebServiceHost";
2. You must also specify the online proxy type for the request to allow the dispatcher to submit it to the remotr server. The proxy class is the one that Visual Studio generates when you add a Web reference to your project
req.OnlineProxyType = typeof(MyWebServiceProxy);
3. To specify the behavior of the request, set the properties of its OfflineBehavior instance using the Behavior property exposed by the Request class.
behavior.ProxyFactoryType = typeof(WebServiceProxyFactory);
4. Set the values of the other OfflineBehavior properties are required. eg Tag, MaxRetries, Stamps


Adding parameters to a Request

Create an array of type Object containig the parameters you want to pass to the Web service by using the static ToArray method ofthe CallParameters helper classs
int customerCode = 1234;
string comment = "New value for comment";
req.CallParameters = CallParameters.ToArray(customerCode, comment);

Handling Callbacks for a Request

1. The RequestDispatcher class calls one of two methods in your application code when a request succeeds or fails.
Create a class to contain these methods
public class MyDisconnectedServiceAgentCallbackClass
{
...
}
2. Create a method that takes
- references to the Request.
- an Object array for the parameters you submitted to the service.
- an Object for any value returned by the web service

public void MyReturnCallbackMethod(Request req, Object[] qParams,
Object result)
{
MessageBox.Show("Request succeeded. Return value is: "
+ result.ToString());
}

3. To get an indication of when a request fails, you create a method that takes as parameters a reference to the Request and an Exception instance. The method should return a value from the OnExceptionAction enumeration, either Dismiss or Retry.
public OnExceptionAction MyExceptionCallbackMethod(Request req,
Exception ex)
{
MessageBox.Show("Your request failed with error: " + ex.Message);
return OnExceptionAction.Dismiss;
}
4. Specify that the dispatcher should call these methods in your class by setting the relevant properties of the OfflineBehavior instance for your request.
req.Behavior.ReturnCallback = new CommandCallback(typeof(MyDisconnectedServiceAgentCallbackClass), "MyReturnCallbackMethod");
req.Behavior.ExceptionCallback = new CommandCallback(typeof(MyDisconnectedServiceAgentCallbackClass), "MyExceptionCallbackMethod");

Adding a Request to a Queue

Pass the configured request to the Enqueue method of the DatabaseRequestQueue instance.
reqManager.RequestQueue.Enqueue(req);

Removing a Request from the Queue

use the Remove method of the DatabaseRequestQueue instance
reqManager.DeadLetterQueue.Remove(req);

Accessing Requests in a Queue

You can reference the pending request queue using the RequestQueue property
IRequestQueue theQueue = reqManager.RequestQueue;
// or:

the "dead letter" or failed request queue using the DeadLetterQueue property
IRequestQueue theQueue = reqManager.DeadLetterQueue;
To remove a request from the queue use the Remove method of the queue.
theQueue.Remove(req);
Dispatching a Single Request Immediately

Call the DispatchRequest method of the RequestManager, passing to it the request to dispatch. The dispatching process is asynchronous.
reqManager.RequestQueue.Enqueue(req);
reqManager.DispatchRequest(req);
Dispatching all pending requests
reqManager.DispatchAllPendingRequests();
Dispatching Specific pending Requests

To dispatch requests having a specific value for their Tag property (say "Sales Order")
reqManager.DispatchPendingRequestsByTag("Sales Order");
Starting and Stoping the Dispatcher Service

To stop the dispatch of requests, call the StopAutomaticDispath method of RequestManager.
if (reqManager.Running)
{
reqManager.StopAutomaticDispatch();
}
To start the dispatch of requests, call the StartautomaticDispatch method of the RequestManager
if (! reqManager.Running)
{
reqManager.StartAutomaticDispatch();
}

Friday, August 31, 2007

The Connection Monitor Application Block

The Connection Monitor Application Block provides the following features

Network connectivity - Network status changes are detected when the connectivity status of physical network adapters changes.
Connectionmonitoring - this feature provides an indication of the current status of physical network adapters.
Pricing - Applications can choose whether to use a network, depending on the current connection's price.

you can use the Connection Monitoring Application Block to detect changes in connectivity to networks. There are two types of networks

1. Logical networks
2. Physical networks

The following are examples of logical networks
1. The internet
2. A corporate or home network
3. A virtual private network
A logical network is a collection of network addresses for a set of resources required by an application.
A physical network adapters include wired and wireless adapters.

Network Class - represents a logical network and exposes the network name and address.
NicConnection Class - provides the capability to detect if the application has a connection to a network.
DesktopConnection Class - this represents a local connection.


Configuring the Connection Monitor Application Block

Configuration information defines the logical networks and physical network adapters that you want to monitor.
with the following configuration section example, the application block will monitor connection to two logical networks and one physical network adapter.
<connectionmonitor>
<networks>
<add name="Intranet" address="http://contoso">
<add name="Internet" address="http://www.microsoft.com">
</networks>
<connections>
<add type="WiredConnection" price="1">
</connections>
</connectionmonitor>

Configure the Connection Monitor Application block

<configsections>
<section name="ConnectionMonitor" type="Microsoft.Practices.SmartClient.ConnectionMonitor.Configuration.ConnectionSettingsSection, Microsoft.Practices.SmartClient.ConnectionMonitor">
</configsections>


Creating a Connection Monitor Instance

Call the static CreateFromConfiguration method of the ConnectionMonitorFactory class. You can specify the name of the section in the application's configuration file that contains the definitions of the connections and networks configured for the application, or you can omit this parameter to use the default section name "ConnectionMonitor." This returns the single instance of the ConnectionMonitor service containing details of all the configured connections and networks for the application.

// Use the default section name "ConnectionMonitor."
ConnectionMonitor sampleMonitor = ConnectionMonitorFactory.CreateFromConfiguration();

// Instead, you can specify the section name in the configuration file.
String configurationName = "SampleConnectionSection";
ConnectionMonitor sampleMonitor = ConnectionMonitorFactory.CreateFromConfiguration(configurationName);


If you are building a Composite UI Application Block application, you can add the ConnectionMonitor instance to the Services collection of your WorkItem so that it is available by using ObjectBuilder injection techniques in any other class within the scope of this WorkItem. In general, you should add it to the root WorkItem of your application.

myWorkItem.Services.Add(sampleMonitor);

Referencing the Connection Monitor Service

1. If you have stored an instance of the ConnectionMonitor class in your WorkItem.
You can use a [ServiceDependency] attribute

public class MyNewClass
{
private ConnectionMonitor sampleMonitor;

public MyNewClass([ServiceDependency] ConnectionMonitor cm)
{
this.sampleMonitor = cm;
}
...
}


2. Alternatively, you can expose a public property for the ConnectionMonitor and have ObjectBuilder set it to the ConnectionMonitor instance in the WorkItem.

public class MyNewClass
{
private ConnectionMonitor sampleMonitor;

[ServiceDependency]
public ConnectionMonitor ConnectionMonitor
{
get { return this.sampleMonitor; }
set { this.sampleMonitor = value; }
}
...
}


3. Another approach is to directly query the Services collection of the WorkItem to obtain a reference to the service you want.

public class MyNewClass
{
private ConnectionMonitor sampleMonitor;

public MyNewClass();
{
this.sampleMonitor = myWorkItem.Services.Get();
}
...
}



Handling Connectivity Change Events

The Network and Connection classes both raise a StateChange event when their state changes.

public void StateChangeHandler(object sender, StateChangedEventArgs e)
{
if (e.IsConnected)
{
MessageBox.Show("Now connected");
}
else
{
MessageBox.Show("Now disconnected");
}
}


Connect your event handler to the StateChanged event of the Connection or Network you want to monitor.


conn.StateChanged += StateChangeHandler;
netwk.StateChanged += StateChangeHandler;


The Connection class exposes a method named UpdateStatus that you can call to raise the StateChanged event and obtain information through your event handler on the connectivity status.

conn.UpdateStatus();



Creating Connections and Networks

You can programmatically create connections and networks and add them to or remove them from the Connection Monitor Service.

1. To create a new connection instance, call he constructor of the appropriate concreate class and specify the name and the price for this connection.
// Create a new NicConnection instance.
NicConnection conn = new NicConnection("NicConnection", 6);

2. Use the Add method of the ConnectionCollection class to add the new connection instance.

// Add it to the ConnectionMonitor Connections collection.
sampleMonitor.Connections.Add(conn);

Thursday, August 30, 2007

Objectbuilder

ObjectBuilder is a framework for creating dependency injection systems.
It allows to customize how an object is created.
To support component independence, a componenent must be able to use another component without requiring a change to the source code of the component to be used.
It using attributes CreateNew and ServiceDependency.

working with ObjectBuilder
1. Creating new Objects
2. Locating a service
3. Registering a service
4. Registering a constructor

Creating New Objects
The NewTransferView class requires an instance of the NewTransferViewPresenter class but does not contain code to instantiate an instance. Instead, the NewTransferView class uses the CreateNew attribute.
[CreateNew]
public NewTransferViewPresenter Presenter
{
get { return _presenter; }
set
{
_presenter = value;
_presenter.View = this;
}
}
The CreateNew attribute instructs ObjectBuilder to instantiate and initialize an instance of a NewTransferViewPresenter when the NewTransferView is created. When the property is set, the View property of the presenter is used to connect this implementation of the INewTransferView interface to the presenter (the View property is defined in the Presenter base class).


Locating a Service

You can add the ServiceDependency attribute to a property in your class to declaratively obtain a reference to a service. The property specifies the type of service or interface you require, as shown in the following code. When this attribute is present, ObjectBuilder locates an instance of the service and passes back a reference to it. To locate the service, ObjectBuilder first looks in the current WorkItem. If the service is not found, ObjectBuilder then looks at the services in the parent WorkItem. If the service is not found, ObjectBuilder throws an exception.
private IAccountServices _accountServices;

[ServiceDependency]
public IAccountServices AccountServices
{
set { _accountServices = value; }
}

Registering a Service

You can programmatically register a service. To do this, call the Add method or AddNew method of the Services collection of the WorkItem within which you want to use the service. This can be the root WorkItem or a module WorkItem. To use an existing service instance you have already created, use the Add method.
moduleWorkItem.Services.AddNew();

Registering a Constructor

A class can contain more than one constructor. ObjectBuilder first looks for any constructor decorated with the [InjectionConstructor] attribute (there can be only one of these) and uses this constructor if found. If there is no decorated constructor, yet there is only one constructor, it will use that constructor.
public class CustomersListViewPresenter
{
private CustomersController _controller;

[InjectionConstructor]
public CustomersListViewPresenter ( [ServiceDependency] CustomersController controller)
{
_controller = controller;
}
...
}

Building Custom UIElementAdapters

Create a custom UIElement Adapter

1. Add a new class to the shell application
2. Add references and using statements for the following libraries
Microsoft.Practices.CompositeUI
Microsoft.Practices.CompositeUI.WinForms
System.Windows.Forms
3. Inherit the class from
a. IUIElementAdapter - for specialized implementation

OR

b. UIElementAdapter - for basic common behavior
4. Implement the members of the interface as follows
a. Add - this method should add an element to the control
b. Remove - this method should remove an item from the specified control
If you want to be able to register extension sites using an instance of the control, you must also create factory for the types of control your adapter handles.


Create a UIElement adapter factory

1. Add a new class to the shell application
2. Specify that the class will implement the IUIElementAdpaterFactory interface from the
Microsoft.Practices.CompositeUI.UIElements namespace
public class MyAdapterFactory : IUIElementAdapterFactory
{
...
}
3. Implement the IUIElementAdapterFactory interface. You must provide the Supports method that determines whether the object passed to the method is of the right type. For example, if your adapter is designed to work with the Windows Forms TreeNode class, the code you require is:
public bool Supports(object myElement)
{
return (myElement is TreeNode);
}
4. You must also implement the GetAdapter method to return an instance of your custom adapter that is suitable for the object type:
public IUIElementAdapter GetAdapter(object myElement)
{
return new MyTreeNodeAdapter(...);
}
Once you have created the custom adapter factory, you must register it with the adapter factory catalog.


Register a UIElement adapter factory in the adapter factory catalog:


Override the AfterShellCreated method in your application class to get a reference to the IUIElementAdpterFactoryCatalog from the Services collection of the RootWorkItem and call the RegisterFactory method:
public class MyApplication : FormShellApplication<..., ...>
{
...
protected override void AfterShellCreated()
{
base.AfterShellCreated();
IUIElementAdpterFactoryCatalog catalog;
catalog = RootWorkItem.Services.Get();
catalog.RegisterFactory(new MyAdapterFactory());
}
...
}

Developing Applications Using the Composite UI Application Block

Creating a Shell

  1. You create and instantiate a class that inherits from FormShellApplication, and then call its Run method in your Main routine.
    This performs
    1. Creating the default RootWorkItem
    2. Adding the standard set of services
    3. Loading any services and modules that are defined in the profile or configuration of the application.
  2. Override AfterShellCreated method to populated toolbars and menus, or show user-interface elements.
  3. Populate any toolbars or menus in the application by accessing a specific extension site and adding a UIElement to it with the Add method.
  4. Add container controls to create the layout that is required for your form. You can insert your SmartParts into these container controls at design-time.
  5. Override OnRunStarted method to create and display child WorkItems that need to execute when the application starts.

Adding Services


There a 3 ways to add a service.

  1. Specifying in the shell application configuration file.
  2. Add a service programmatically
    Call the Add or AddNew method of the Services collection of the WorkItem
    Add - to use an existing service instance you have already created.
    AddNew - to create a new instance of a service and add it to the WorkItem.
  3. Declare a class to be registered as a service using an attribute and place the Service attribute on a public class.

Creating a Module

1.Create a Module
  1. Create a new class library project or Windows control library project.
  2. Add referece
    Microsoft.Practices.CompositeUI
    Microsoft.Practices.ObjectBuilder
  3. Add a ModuleAttribute to the project so that other modules can identify your module.
    Add the following line to the AssemblyInfo.cs file
    [assembly: Microsoft.Practices.CompositeUI.Module("mainMod")]
2. Create a module initializer
  1. Create a new public class inherit from the Microsoft.Practices.CompositeUI.ModuleInit
  2. To add services programmatically to the module, override the AddServices method of the ModuleInit class.
  3. To display the user-interface or perform custom logic on startup, override the Load method of the ModuleInit class.
3. Add dependencies to the module
Either in the ModuleInit class or in the AssemblyInfo file, add module dependencies as
[assembly: Microsoft.Practices.CompositeUI.ModuleDependency("TheModuleYouDependOn")]
4. Load a Module
Edit ProfileCatalog.xml to list the appropriate modules to load
Getting References to Services

1. Obtain reference to a service programatically
Call the Get method of the Services collection of the WorkItem, passing in the type of service as

IMyService myServ = (IMyService)myWorkItem.Services.Get(typeof(IMyService));

// or using generics
IMyService myServ = myWorkItem.Services.Get();
2. Obtain a reference to a service declaratively
Add the ServiceDependency attribute to a property in your class that is of the type of service or interface you require.
3. Obtain a reference to a service of a specific concrete type
Add the Type property to the ServiceDependency attribute

private ThisService service;

[ServiceDependency(Type=typeof(IMyService))]
public ThisService MyService
{
set { service = value; }
}

Creating Custom Services.

  1. Add a new interface to an appropriate module.
  2. Add members that the interface will define.
  3. Add a new class to the module or the shell.
  4. Inherit from the interface and add the required functionality to the members.
  5. Add the Service attribute to the class definition as
[Service(Type=typeof(IMyService))]
public class MyService : IMyService


Creating and Showing SmartParts

1. Create a SmartPart
  1. Add a user control to your project.
  2. Add a reference to the Microsoft.Practices.CompositeUI.SmartParts
  3. Add the SmartPart attribute to the control class as
[SmartPart]
public partial class MySmartPart : UserControl

2. Display a SmartPart in a SmartPartPlaceholder
Create an instance of the SmartPart user control using the AddNew method of the SmatrParts or the Items collection of the WorkItem. You pass a string to the AddNew method to assign a name to the SmartPart. At runtime, the SmartPart is automatically loaded into the SmartPartPlaceHolder that specifies the SmartPart name for its SmartPartName property.

CustomerSmartPart csp;
csp = myWorkItem.SmartParts.AddNew("CustomerSP");

3. Display a SmartPart in a Workspace
  1. Create an instance of the SmartPart user control with the AddNew method of the SmartParts collection of the WorkItem.
  2. Call the Show method of the Workspace in which you want to show the SmartPart
    public class MyWorkItem : WorkItem
    {
    protected override void OnRunStarted()
    {
    base.OnRunStarted();
    CustomerSmartPart csp = this.SmartParts.AddNew();
    Workspaces["tabbedArea"].Show(csp);
    }
    }

  3. If you want to specify advanced preferences for how the control will appear, you can create a SmartPartInfo instance of the type is appropriate for the workspace you are using.


Developing with the MVC Pattern

1. Build a controller class
  1. Create a new class and inherit from Microsoft.Practices.CompositeUI.Controller.
  2. Implement your own methods to control the view.
  3. If you require data to be stored in the WorkItem shared state, use the State property of the base class, or the State attribute, as
[State("Customer")]
public Customer customer
{
get { return (Customer)State["Customer"]; }
set { State["Customer"] = value; }
}

2. Build a view class
  1. Create a form, SmartPart, or user control to display information to the user.
  2. Create a class to manage the data displayed in the view.
  3. Add the [CreateNew] attribute to inject an instance of the dependent class through a property,

private MyControllerClass myController;

[CreateNew]
public MyControllerClass Controller
{
set { myController = value; }
}

3. Implement the MVC pattern
  1. Create a WorkItem as

    public class MyWorkItem : WorkItem
    {
    }

  2. Override the OnRunStarted method of the WorkItem to create an instance of the view. It automatically creates the corresponding controller instance.

protected override void OnRunStarted()
{
base.OnRunStarted();
SampleView view = this.Items.AddNew();
workspace.Show(view);
}


Publishing and Subscribing to Events

There are two ways of registering publications or subscriptions for an event
  1. Using Attributes
  2. Programmatically - write code to get an instance of the EventTopic you want to publish or subscribe to via the EventTopics collection of a WorkItem instance, and then call its methods to register and unregister publishers and subscribers. but this is not required for most common cases.

1. Publishing Events
using the EventPublication attribute on an event declaration. This attributes uses two parameters: the event name and the event scope.

  1. Publish event available in all WorkItem instances
    [EventPublication("event://UpdatesAvailable", PublicationScope.Global)]
    public event SomeEventHandler UpdatesAvailable;
  2. Publish a event available only to the local and descendant WorkItems
    [EventPublication("event://UpdatesAvailable", PublicationScope.Descendants)]
    public event SomeEventHandler UpdatesAvailable;
  3. Publish an event available only to the local workItem
    [EventPublication("event://UpdatesAvailable", PublicationScope.WorkItem)]
    public event SomeEventHandler UpdatesAvailable;

2. Subscribing to Events
[EventSubscription("event://UpdatesAvailable")]
public void NewUpdates(object sender, SomeEventArgs numUpdates)
{
MessageBox.Show(numUpdates.ToString(), "Updates available");
}

3. Running Events on the User Interface Thread
Add a second parameter to the EventSubscription attribute as
[EventSubscription("event://UpdatesAvailable", Thread=ThreadOption.UserInterface)]
4. Running Events on a Background Thread
Add a second parameter to the EventSubscription attribute as
[EventSubscription("event://UpdatesAvailable", Thread=ThreadOption.Background)]

Working with WorkItems

1. Create a WorkItem
  1. Create a new class and inherit from Microsoft.Practices.CompositeUI.WorkItem
  2. Override the OnRunStarted method of the base WorkItem to perfoem an initialization required and to display the appropriate view.
    protected override void OnRunStarted()
    {
    base.OnRunStarted();
    SummaryView view = this.Items.AddNew();
    workspace.Show(view);
    }

  3. Implement methods to provide any functionality required to manage the views.
  4. If a parent WorkItem contains state that is required in this WorkItem, use the State attribute to inject state items into the child WorkItem automatically.
[State("Customer")]
public Customer Customer
{
get { return (Customer)State["Customer"]; }
set { State["Customer"] = value; }
}

2. Invoke a WorkItem
myWorkItem.Run();
3. Inject state into child SmartParts in a child WorkItem

  1. In the parent WorkItem, set the state so that adding a child WorkItem to the container injects the state into it, as
    public void ShowCustomerDetails(Customer custmr)
    {
    // set state for injection into child WorkItem
    State["Customer"] = custmr;
    ChildWorkItem myChild = this.WorkItems.AddNew();
    myChild.Run();
    }

  2. In the child WorkItem, use the State attribute to indicate that a parent WorkItem should inject the property into the child WorkItem.
// in child WorkItem
[State("Customer")]
public Customer TheCustomer
{
get { return (Customer)State["Customer"]; }
set { State["Customer"] = value; }
}


Showing UIElements

You can create menu items that are accessible from all the SmartParts in a shell.
To Create and display such user interface elements(UIElements),

1. Call the RegisterSite method of the UIExtesionSites collection of the root WorkItem, passing the site name for the element and the control where it will be located.
RootWorkItem.UIExtensionSites.RegisterSite("MainMenu", Shell.MainMenuStrip);
2. In the AftershellCreated method of your class that inherits from FormShellApplication, declare a local variable of the type of element to display on the control as
ToolStripMenuItem item = null;
3. Initiate this variable, passing in the appropriate information for the element type. The following code shows hows to instantiate a menu item and specify the text to display on it.
item = new ToolStripMenuItem("Name");

4. Call the Add method of the specific UIExtensionSite, passing in the elemnt you created earlier.
MyWorkItem.UIExtensionSites["MainMenu"].Add(item);


Registering Commands


1. To declare a Command
Add the CommandHandler attribute to the declaration specifying a command name as

[CommandHandler("ShowName")]
public void ShowName(object sender, EventArgs e)
{
MessageBox.Show("My name is Joe");
}
2. Associate a Command with UIElement
Call the AddInvokre method of the specific Command collection to wire up the Click event, passing in a reference to the menu item and the event name:

MyWorkItem.Commands["ShowName"].AddInvoker(item, "Click");

Wednesday, August 29, 2007

Composite UI application Block

The Composite UI application Block builds on the knowledge and feedback gained from the User Interface Process (UIP) Application Block

Flow of Components

In a Composite Application Block application, a WorkItem is a container. A component can access any other component that is in the same container. Components flow from a parent container to a child container.

The root of a composite UI Application Block application is the shell. The shell typically contains workspaces, UI Extension Sites, commands, and services.

The CAB supports the customization of an application using solution profiles in a catalog. A solution profile is a list of modules that should be loaded into an application.

After a module is loaded, it can add elements to the shell's UI Extension sites.

WorkItems
A WorkItem is a run-time container for components that are working together to fulfill a use case. The components can be both visual and non-visual parts of the application, such as SmartParts, controls, and service.

Services
Services are objects that are used by many components in the application.

Module Initialization
When CAB loads a module, it uses reflection to determine whether the module includes a class that implements the IModule interface.

Loading Modules
By default, it uses an XML catalog file to determine the modules to load.

Wiring the Parts Together with the Injection System
To support component independence, a component must be able to use another component without requiring a change to the source code of the component to be used. The CAB application does not create instances of another component by directly constructing an object (using new). Instead, CAB using the attributes such as CreateNew and ServiceDependency. These attribute support the injection of objects at run time.
CAB uses a system named ObjectBuilder to create and inject instances of objects of the appropriate type into the application at run time.

The CreateNew attribute instructs ObjectBuilder to initiate and initialize an instance of an object.

Locating a Service
ObjectBuilder first looks in the current WorkItem, then in parent WorkItem, This process continues until reaches the root WorkItem. If the service is not found, ObjectBuilder throws an exception.

Registering a Service
You can use the Service attribute on a public class to declare a class to be registered as a service in the root WorkItem.

MVC - The view passes user interactions to the controller, which updates the data model. The data model is responsible for updating the view.

MVP - The View passes user interactions to the presenter, which updates the data model. The presenter is responsible for updating the view.

Component
Visual and non-visual parts of an application, such as SmartParts, services, and controls.

Container
A Class that contains components and services.



Design of SubSystems

1. Design of the Application Shell
The class derives from FromShellApplication creates the root WorkItem, which contains the services and child WorkItems within the application.
2.Design of the WorkItem
Container for components consists of SmartParts, controllers, services, UIElements, and other components. The WorkItem provides a Run method that causes the protected and virtual OnRunStarted method to execute, and fires the RunStarted event. You can activate and deactivate WorkItems as required. A WorkItem has a State property, which enables all the components in that WorkItem to aceess shared state. Modifying data in the State property raises the StateChanged event.
3. Design of Workspaces
Workspaces are components that encapsulate a particular visual way of displaying controls and SmartParts.
The CAB includes the following types of workspaces:
a. WindowWorkspace
b. MdiWorkspace
c. TabWorkspace
d. DeckWorkspace
e. ZoneWorkspace
Workspaces can show, hide, activate, or close a set of controls.
All workspaces implement the IWorkspace interface that includes the following members:
-Activate (Objet smartPart)
-Show (Object smartPart)
-Show (Object smartPart, ISmartPartInfo smartPartInfo)
-Hide (Object smartPart)
-Close (Object smartPar)
-Object ActiveSmartPart()
-event EventHandler SmartPartClosing
-event EventHandler SmartPartActivated
WindowSmartPartInfo
This component to specify that a SmartPart should be displayed modally. You add the component to your form, set its Modal property to true, and then pass this instance as the second parameter to the workspace Show method.
TabSmartPartInfo
Specify whether the tab page where the SmartPart will be shown should be activated, as well as its location related to other tabs.
ZoneSmartPartInfo
specify the zone that SmartPart should be displayed in.
SmartPartInfo
It is a generic SmartPartInfo component to specify the Title and Description for a SmartPart.

Design of UIElementAdapters


Shared UIElements that module developers can access are menus, toolbars, status bars, progress bars, sidebars, action panes, the notification trays etc. Shell developers are responsible for the creation of these components, and module developers can create instances of the component and access their properties. Each UI Element requires a specific adapter to handle its manipulation. A string value called the extension site is used to identify elements when interacting with and adding child elements to that site. The application block provides a UIExtensionSites catalog for each WorkItem.

Design of Commands

Enable you to write one event handler that is associated with more than one UIElement, and associate one UIElement with multiple command handlers.
A command can be in one of the three states defined in the CommandStatus enumeration: Enabled, Disabled, and Unavailable.

Design of the Injection Model

1. Design of ObjectBuilder
ObjectBuilder create and inject instances of objects of the appropriate type into the application at runtime.
2. ObjectBuilder Architecure
It uses a pipeline of strategies that allow multiple operations to take palce as objects are instantiated and prepared for use. This allows you to control the order that the processes take place.
3. ObjectBuilder Methods
a. BuildUp method
BuildUp(locator, type, id, instance, policies[] );
BuildUp(locator, id, instance, policies[] );
b. TearDown method
TearDown(instance);
takes an existing object instance and run it back through the strategy chain. This process can remove features added to the object during the BuildUp process if you want to re-use the object.
4. PolicyList
set of policies, each represented by classes that implement the IBuilderPolicy interface, that influence the way that an object is created by ObjectBuilder.
1. Transient policies are those generated automatically by the strategies in ObjectBuilder or through reflection over the attributes on the methods and properties declared in the class file.
2. Permanent policies are those you create by implementing the IBuilderPolicy interface.
5. Pipeline Stages
a. Precreation - occurs before ObjectBuilder creates a new instance of the object.
b. Creation
c. Initialization
d. Postinitialization
Design of the Services

1. Design of the Module Enumerator Service
CAB supports the customization of an application using solution profiles in a catalog. A solution profile is a list of modules that should be loaded into an application. A catalog can contain only one profiles.

The XML file catalog can specify which roles a user running the application must be a member of in order to use the module. You can specify the required role membership for each module in the catalog itself.

2. Design of the Event Broker Service
Enables to implement loosely coupled communications between the components in application.

Available ThreadOption values for EventSubscription are
  1. ThreadOption.BackGround - handler should be called on a separate thread.
  2. ThreadOption.Publisher - default. handler should be called synchronously on the publisher's thread.
  3. ThreadOption.UserInterface - called on the user interface thread, so it is safe for it to modify user interface elements.
3. Design of the Module Loader Service
The ModuleLoaderService uses the information returned from the IModuleEnumerator to determine which modules should be loaded at run time. It then loads the specified assemblies, check them for any ModuleDependency attributes and builds a list of modules to initialize. It instantiates the module initializer for each module and add it to the application shell so that the initializer class can subscribe or publish events and access services added by other modules.

Application Initialization Sequence

Types of Applicaion Classes
  1. FormShellApplication
  2. ApplicationContextApplication
  3. WindowsFormsApplication
  4. CabShellApplication
  5. CabApplication
1. FormShellApplication
This class is used in applications that need to show a main window as part of their start-up process.
2. ApplicationContextApplication
This class is used in applications that do not show a main window as part of the start-up process, or applications that have complex requirement for creation of the UI before the application starts.
3. WindowsFormsApplication
This class is used in any shell built on Windows Forms. Does not change or extend the start-up sequence.
4. CabShellApplication
This class is used in applications that require a shell (which may or may not be a window) to be shown at start-up.
5. CabApplication
This class manages the fundamental steps of initializing a CAB application. This is the most generic type of application class.
Application Startup Sequence
  1. RegisterUnhandledExceptionHandler
  2. Create Object Builder and add strategies
  3. create the root WorkItem
  4. Create and initialize the visualizer
  5. Add the required services
  6. Add any additional services
  7. Authenticate the user
  8. Load any services or WorkItemExtensions present in the shell assembly
  9. Perform BuildUp of the root WorkItem
  10. Find modules enumerated by the catalog and load them
  11. Initialize workItemExtensions with the root WorkItem
  12. Run the root WorkItem
  13. Call the Start method
  14. clean up references and dispose of instances

Developing Applications Using the Composite UI Application Block

The basis of a typical CAB application is the FormShellApplication class. You create and instantiate a class that inherits from FormShellApplication, and then call its Run method in your Main routine.
It creating
  1. Creating the default RootWorkItem
  2. Adding the standard set of services
  3. Loading any services and modules that are defined in the profile or configuration of the application.

Override AfterShellCreated to populate toolbars and menus or show user-interface elements.
Override OnRunStarted method to create and display child workItems that need to execute when the application starts.

To show a SmartPart that will be added at runtime
  1. Use a SmartPartPlaceHolder control.
  2. Add a workspace of a certain visual style.
Basic stages
  1. Create a class that inherits from FormShellApplication. In the Main routine, create an instance of this shell class, and call its Run method.
  2. Override the AfterShellCreated method to initialize the user interface. You can show different types of UIElements in the shell form by registering extension sites on the tool strip and menu strip where modules can add their UIElements at run-time.
  3. Populate any toolbrs or menus in the application by accessing a specific extension site and adding a UIElement to it with the Add method
  4. Add container controls to create the layout that is required for your form. Insert SmartParts into these container controls at design-time.
  5. Write code for any other methods you need to override.

Saturday, August 18, 2007

Designing Smart Client Based on CAB and SCSF

Architectural Guidance for Composite smart Client

Introduction

Enables the components to communicate in a loosely coupled way so the modules do not really depend on each other.
Different applications are dynamically plugged in to a central infrastructure. Loaded and initialized on demand based on the user's security context.


PART 1 : Architectural Guidance for Composite Smart Clients

CAB providing following functionality

  1. Dynamically loading independent yet cooperating modules into a common shell.
  2. Event broker for loosely coupled communication between modules and parts of modules.
  3. Ready-to-use Command pattern implementation.
  4. Base classes for Model-View-control(MVC) pattern implementation.
  5. Framework for pluggable infrastructure services ranging, such as authentication services, authorization services, module location, and module loading services.
WorkItem - Container for managing objects. Workspaces holding these objects

Service - encapsulate functionality that is common for the whole client application, for a specific module, or just for WorkItems within a certain hierarchy of WorkItems.

Module - Multiple, logically related WorkItems into a single unit of deployment.

ProfileCatalog - specifies which modules and services need to be loaded into the application.

ModuleLoader - responsible for loading all the modules specified in a profile catalog.

ModuleInit - Each module consists of a ModuleInit class, which is responsible for loading all the services and WorkItems of a module.

Shell application - responsible for initializing the application. It dynamically loading modules, launching the base services, starting the main form(Shell).

Shell - main form of the application. The shell always hosts the root workItem.

Workspace - is a control responsible for holding and displaying user interface elements created by WorkItems. Workspaces are added to the shell.

UIExtensionSite - special placeholders for extending fixed parts of the Shell such as menus, tool strips or status strips.

Command - is a base class of CAB for implementing the Command pattern.

Model - cient side business entity a WorkItem processes.

View - implements only UI logic.

SmartPart - A SmartPart is a .NET Framework user control with the [SmartPart] attribute applied.

Controller - is a class that implements the logic for modifying a model.

Objectbuilder - creating objects that require specific builder strategies to be created or that need features.

DependencyInjection - create or initialize properties/members of objects with dependent objects. ObjectBuilder provides this functionality.


Smart Client Software Factory.

Designing composite smart clients takes place in three iterations
  1. Non-UI related functionality that is common to all the use cases are candidates for central services.
  2. Create detailed use case diagrams. Use cases are good candidates for becoming WorkItems. Relationships between use cases are candidates for using either the Command pattern or the event broker subsystem of CAB. Close related WorkItems are good candidates for being packaged into modules together.
  3. Refine use case diagrams. WorkItems that are reused independently of other packaged into the same module or used isolated from their parent WorkItems so that they are better suited as first-level WorkItems.

Application Shell-Service and Infrastructure Service Design

One of the first parts to design and implement for CAB-based smart client is the shell.
The shell is the actual application that is responsible for
  1. loading and initializing base client services
  2. loading and initializing modules
  3. providing the basic UI of the application
  4. hosting the SmartParts loaded by first-level Workitems.
Common user interface elements that need to be added to the shell are the following:
  1. Menus, toolbars, and tool strips
  2. Navigation controls, such as the Outlook toolbar
  3. A common message pane for having a central point to display messages for the user
  4. Task panes, taskbars
  5. Context panes that display information based on the current situation of the user

These elements are integrated into a shell with Workspaces and UIExtensionSites.
workspaces are used for completely replacing parts of the UI.
UIExtesionSite is used for extending existing parts of the shell.


Infrastructure Services

encapsulate functionality common to all modules and components loaded into the smart client. CAB introduces many infrastructure services, such as an authentication service or a service for loading a catalog of modules configured somewhere (ProfileCatalog.xml)
  1. Authorization service
  2. Web service agents and proxies encapsulating calls to Web services and offline capability
  3. Context services to manage user context across WorkItems
  4. Configuration services for accessing application-centric configuration
  5. Deployment services using ClickOnce behind the scenes for programmatic, automatic updates

Identifying WorkItems

WorkItems are components responsible for encapsulating all the logic for specific tasks the user wants to complete with the application.
A WorkItem itself contains or knows about one or more SmartParts (views) with their controller classes and models.
Each CAB application has one RootWorkItem that acts as the central entry point for global services and WorkItems added by modules.

There are two ways for identifying WorkItems for your composite smart client
  1. use case-driven approach
  2. business entity-driven approach


Use Case-Driven Strategy

One use case will be encapsulated into a WorkItem.
Pure sub-use cases are sub-WorkItems that are not accessible from outside their parents.
Use cases used by many other use cases in addition to its own parent need to be accessible either directly or through their parent WorkItem.


The Role of Root Use Cases
They are responsible for managing state required for all sub-WorkItems and providing the right context for all their sub-WorkItems.

It accomplish the following steps when being loaded:
  1. Add services required by this set of WorkItems
  2. Retrieve service references required by this WorkItem
  3. Register commands for launching sub-WorkItems
  4. Add UIExtensionSites to allow starting into WorkItem-code via previously registered commands
  5. Create instances of sub-WorkItems when they are needed
  6. Create and register instances of SmartParts required by the WorkItem itself

Summary
The following steps identify WorkItems based on use case diagrams for CAB-based composite smart clients:
  1. Create the use case diagram
  2. Map each use case to one WorkItem in CAB
  3. Exclude use cases not directly related to your smart client
  4. Analise relationships between use cases, If use cases are used by other use cases in addition to their parent, they are candidates for becoming first-level WorkItems
  5. Analise requirements of use cases. If use cases do not depend on state or context of their parents, and vice-versa, they are also candidates for first-level WorkItems

Packaging WorkItems into Modules

A module is a unit of deployment for CAB-based smart clients logically related WorkItems that address the same space of business into a module.
Modules are configured in a profile catalog. These modules can be configured based on role membership of a user.
If you want to reuse WorkItems independently from others, it makes sense to encapsulate them into separate modules.


CAB Infrastructure Usage Guidelines

Relationships between use cases represent interactions between use cases.
CAB supports two types of interactions between components
  1. Active communication - through an implementation of the command pattern
  2. Passive communication - through its event broker system
Using the Event Broker System

provides a pre-built infrastructure for loosely coupled events. That means any component loaded into CAB can publish events, and other components can subscribe to these events without knowing who the publishers are.
The event broker is used while a CAB component wants to provide information to others without getting immediate response and without requiring knowing who receives events.
If you need immediate response or need to know exactly who a component is talking to, the event broker is the wrong system.

Using the Command Pattern

If your component needs something to be done immediately by another component or is passing control on to this other component.
Use commands for launching WorkItems (or sub-WorkItems) instead of events.



Part 2: Developer's Guidance

Steps for creating a CAB-based Smart Client
  1. Create a smart client project using SCSF.
  2. Creare the shell and its components, and design the shell's UI.
  3. (Optional) Create and Register services.
  4. (Optional) Configure CAB infrastructure services if you have created ones in step 3.
  5. Create CAB modules containing WorkItems with SmartParts and their presenters.
  6. Configure and run the application.

1. Create a smart client project using SCSF.


Projects created by the smart client software factory

a) Infrastructure.Interface
Defines interfaces for basic services created by SCSF.

The added services created by SCSF are
  1. Entity Translator Base Class - Base classes for building translators of entities.
  2. Basic SmartPart Info Classes - when you want to display additional information for a SmartPart when it is being added to a workspace. For example, if you want to display a caption in a tab created within a tabbed workspace.
  3. ActionCatalog Service - allows you to define specific methods of your classes as actions.
  4. DependentModuleLoader - you can specify that one module depends on others to be loaded before it gets loaded itself.
  5. WebServiceCatalog Service - you can retrieve the modules to be loaded at startup of your smart client from a Web service.
b) Infrastructure.Library
Contains the implementations of the additional services generated by SCSF.

c) Infrastructure.Module
An empty module (default root WorkItem for a module) where you can add your own infrastructure service.

d) Infrastructure.Layout
A project SCSF creates if you selected that you want to put the shell's layout into a separate module. It contains a SmartPart and a presenter for this SmartPart for the shell layout.

e) Shell
The actual Windows-based application of the smart client that contains the configuration and the actual main form that hosts the shell layout


2. Creating the shell and its Components
  1. Design the basic UI of the shell and add CAB UI components.
  2. Register UIExtensionSites for UI parts that are extended but not replaced by loaded modules.
  3. Create interfaces for UI-related basic shell services.
  4. Implement and register UI-related basic shell services
3. Creating and Registering New Services
You can start creating and registering other services commonly used by components loaded into your smart client.

4. Developing CAB Business Modules
WorkItems themselves are responsible for launching sub-WrokItems and SmartParts as required for completing a use case.

Steps for Creating a CAB Business Module

  1. Add the new business module using the Smart Client software Factory.
  2. Add new WorkItems to the created module. Each Work Item encapsulates a use case.
  3. (Optional) Create a new sub-WorkItem.
  4. Add state required for a WorkItem and its sub-WorkItems.
  5. Add the SmartParts required for a WorkItem.
  6. Create commands for launching first-level WorkItems.
  7. Create an ActionCatalog for creating UIExtensionSites.
  8. Publish and receive events as required.
4. Configure the Application
There are two parts you need to configure: the catalog containing the list of modules to be loaded and the application configuration itself. The profile catalog understands dependencies between modules.