Thursday, August 30, 2007

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");

No comments: