Tuesday, May 29, 2007

Stage 2: Creating and Loading the Module

  1. Add new Class Library project named MyModule to the existing solution
  2. In Properties->Build->Output select \bin\Debug folder of ShellApplication project
  3. Save and reopen then, Properties->Outputpath to ..\ShellApplication\bin\Debug
  4. Add Reference
    Microsoft.Practices.CompositeUI.dll
    Microsoft.Practices.CompositeUI.WinForms.dll
    Microsoft.Practices.ObjectBuilder.dll
  5. Create a class named MyWorkItem.cs derived from WorItem and include namespace
    using Microsoft.Practices.CompositeUI;
    public class MyWorkItem : WorkItem
    {
    }
  6. Add a module Initialiser

    1. add class named MyModuleInit.cs derived from ModuleInit and include namespaces

      using Microsoft.Practices.CompositeUI;
      using Microsoft.Practices.CompositeUI.Services;
      using System.Windows.Forms;

      public class MyModuleInit : ModuleInit
      {
      }

    2. Add the following variable to reference the WorkItemTypeCatalogService so that you can access it to register your WorkItem:

      private IWorkItemTypeCatalogService myCatalogService;
      [ServiceDependency]
      public IWorkItemTypeCatalogService myWorkItemCatalog
      {
      set { myCatalogService = value; }
      }

    3. Override the Load method of the ModuleInit class so that it registers your module's WorkItem.

      public override void Load()
      {
      base.Load();
      myCatalogService.RegisterWorkItem<MyWorkItem>();
      }

    4. instruct the CAB to load the new module in 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>


right-click the file ProfileCatalog.xml and click Properties. Change the Copy To Output Directory property to Copy Always.

Stage 1: Creating the Shell and the Form

  1. Create a new Windows Forms application named ShellApplication
  2. rename Form1.cs to ShellForm.cs
  3. Add Reference

    Microsoft.Practices.CompositeUI.dll
    Microsoft.Practices.CompositeUI.WinForms.dll
    Microsoft.Practices.ObjectBuilder.dll

  4. create a custom workitem
    1. create a new class named ShellWorkItem.cs
    2. Inherit class from WorkItem and include namespace
      using Microsoft.Practices.CompositeUI;
      public class ShellWorkItem : WorkItem
      {
      }
  5. modification in program.cs
    1. rename Program.cs to ShellApplication.cs
    2. include namespace
      using Microsoft.Practices.CompositeUI.WinForms;
    3. Replace the static class ShellApplication with a public class that inherits from FormShellApplication
      public class ShellApplication :
      FormShellApplication<shellworkitem,shellform>
      {
      }
    4. [STAThread]
      static void Main()
      {
      new ShellApplication().Run();
      }

Basic Commands...

Creating a shell.
public class MyApplication : FormShellApplication<WorkItem, MyShellForm>
{
}
[STAThread]
public static void Main()
{
new MyApplication.Run();
}

override the AfterShellCreated method
protected override void AfterShellCreated()
{
base.AfterShellCreated();
... your start-up code here ...
}

display a SmartPart in a Workspace
Form1 mainForm = new Form1();
CustomerSmartPart sp = myWorkItem.Items.AddNew<CustomerSmartPart>();
mainForm.deckWorkspace1.Show(sp);

WorkItems.

create a workitem
  1. create a class inherit from Microsoft.Practices.CompositeUI.WorkItem.
  2. override the OnRunStarted method. In this method, add code to perform an initialization required and to display the appropriate view.
protected override void OnRunStarted()
{
base.OnRunStarted();
SummaryView view = this.Items.AddNew<SummaryView>();
workspace.Show(view);
}

Invoke a WorkItem
myWorkItem.Run();


Inject state into child SmartParts in a child WorkItem

steps1: In the parent WorkItem, set the state so that adding a child WorkItem to the container injects the state into it
public void ShowCustomerDetails(Customer custmr)
{
// set state for injection into child WorkItem
State["Customer"] = custmr;
ChildWorkItem myChild = this.WorkItems.AddNew<ChildWorkItem>();
myChild.Run();
}
steps2: 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; }
}

UIElements.
RootWorkItem.UIExtensionSites.RegisterSite("MainMenu", Shell.MainMenuStrip);
ToolStripMenuItem item = null;
item = new ToolStripMenuItem("Name");
MyWorkItem.UIExtensionSites["MainMenu"].Add(item);

Commands.
[CommandHandler("ShowName")]
public void ShowName(object sender, EventArgs e)
{
MessageBox.Show("My name is Joe");
}

associate a Command with a UIElement
MyWorkItem.Commands["ShowName"].AddInvoker(item, "Click");


Services.

add a service by specifying it in the shell application configuration file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="CompositeUI"
type="Microsoft.Practices.CompositeUI.Configuration.SettingsSection,
Microsoft.Practices.CompositeUI"
allowExeDefinition="MachineToLocalUser" />
</configSections>
<CompositeUI>
<services>
<!-- Other services -->
<add serviceType="MyApp.Services.IMyService, MyApp"
instanceType="MyApp.Services.MyService, MyApp"/>
</services>
</CompositeUI>
</configuration>


to add a service programmatically

1. to use an existing service instance already created.
RootWorkItem.Services.Add<CustomerService>(myServiceInstance);

2. to create a new instance of a service
RootWorkItem.Services.AddNew<CustomerService>();


Register a class as a service using attribute.
[Service(typeof(IMyService))]
public class MyService : IMyService
{
}
Services that do not provide different implementations may not implement an interface
[Service]
public class MyService
{
}

declare a class to be registered as a lazy-loaded service.
[Service(typeof(IMyService), AddOnDemand=true)]
public class MyService : IMyService
{
}

Module.

steps1 : Create a module
steps2 : Create a module initializer
steps3 : add dependencies to the module
steps4 : load a module

Create a module
  1. create a new class library or Windows control library project
  2. add reference to Microsoft.Practices.CompositeUI and Microsoft.Practices.ObjectBuilder
  3. add a module attribute to identify this as a module.
  4. [assembly: Microsoft.Practices.CompositeUI.Module("mainMod")] in AssemblyInfo.cs

Create a module Initializer
  1. create a new public class
  2. inherit from Microsoft.Practices.CompositeUI.ModuleInit class.
  3. you can override the AddServices method
  4. you can override the Load method
add dependencies
put following in either in the ModuleInit or AssemblyInfo.cs
[assembly: Microsoft.Practices.CompositeUI.ModuleDependency(
"TheModuleYouDependOn")]
load a module
<?xml version="1.0" encoding="utf-8" ?>
<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile">
<Modules>
<ModuleInfo AssemblyFile="Mod1.dll"/>
<ModuleInfo AssemblyFile="Mod2.dll"/>
</Modules>
</SolutionProfile>

creating reference to services

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

// or using generics
IMyService myServ = myWorkItem.Services.Get<IMyService>();
declaratively
private IMyService service;

[ServiceDependency]
public IMyService MyService
{
set { service = value; }
}


creating Custom Services
steps1: add a new interface to an appropriate module.
steps2: add members that the interface will define.
steps3: add a new class to the module or the shell.
steps4: inherit from the interface and add required functionality to the members.
steps5: add the attribute like following
[Service(Type=typeof(IMyService))]
public class MyService : IMyService

SmartParts.

steps1: add a user control to project
steps2: add a reference to the Microsoft.Practices.CompositeUI.SmartParts
steps3: add the attribute as following
[SmartPart]
public partial class MySmartPart : UserControl

display a SmartPart in a Workspace
public class MyWorkItem : WorkItem
{
protected override void OnRunStarted()
{
base.OnRunStarted();
CustomerSmartPart csp = this.SmartParts.AddNew<CustomerSmartPart>();
Workspaces["tabbedArea"].Show(csp);
}
}
implement the MVC pattern
protected override void OnRunStarted()
{
base.OnRunStarted();
SampleView view = this.Items.AddNew<SampleView>();
workspace.Show(view);
}
Publishing Events
[EventPublication("event://UpdatesAvailable", PublicationScope.Global)]
public event SomeEventHandler UpdatesAvailable;

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

run an event on a background thread
[EventSubscription("event://UpdatesAvailable",
Thread=ThreadOption.Background)]

Monday, May 28, 2007

Basic Commands

UI Elements.
RootWorkItem.UIExtensionSites.RegisterSite(“FileMenu”, Shell.MainMenuStrip);


ToolStripMenuItem printItem = new ToolStripMenuItem("Print");
RootWorkItem.UIExtensionSites[“FileMenu”].Add(printItem);
WorkItems.
adding services to a workitem. ie creates an instance
WorkItem.Services.AddNew<CustomerFinderService, ICustomerFinderService>();
creates an instance of the OfficerView class
WorkItem.SmartParts.AddNew<OfficerView>();
get another component in a workitem
ICustomerFinderService customerFinderServcie =
WorkItem.Services.Get<ICustomerFinderService>();

EVents.
publishing
[EventPublication("topic://UpdatesAvailable", PublicationScope.Global)]
public event EventHandler<DataEventArgs<UpdateData>> UpdatesAvailable;
// or
[EventPublication("topic://UpdatesAvailable", PublicationScope.Global)]
public event EventHandler UpdatesAvailable;
subscription
[EventSubscription("topic://UpdatesAvailable")]
public void SomethingHappened(object sender, DataEventArgs<UpdateData> e)
{ ... }

Module.
Module Dependencies
[assembly: ModuleDependency("BranchSystems.Module")]
Loading Modules- default file is ProfileCatalog.xml
<?xml version="1.0" encoding="utf-8" ?>
<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile" >
<Modules>
<ModuleInfo
AssemblyFile="GlobalBank.AppraiserWorkbench.AppraiserWorkbenchModule.dll" /></Modules></SolutionProfile>
services.
Registering a service
[Service(typeof(IMyService))]
public class MyService : IMyService
{
}

Locating a Service.
private IMyService service;

[ServiceDependency]
public IMyService MyService
{
set { service = value; }
}


Thursday, May 24, 2007

Object Builder.

create objects and perform dependency injection.
It manages the processes performed on objects during construction and disposal.

attributes - [CreateNew] and [ServiceDependency]
CreateNew - This attribute tells the dependency injection system to always create a new one of whatever it is you need.
Dependency - This is a general-purpose attribute with four optional parameters: Name, NotPresentBehavior, Createype, SearchMode
methods - BuildUp and TearDown.

BuildUp(locator, type, id, instance, policies[] );
BuildUp(locator, id, instance, policies[] );

Creating New Objects.
[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.

Locating a Service.

You can add the ServiceDependency attribute to a property.
The property specifies the type of service or interface you require.
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.
private IAccountServices _accountServices;
[ServiceDependency]
public IAccountServices AccountServices
{
set { _accountServices = value; }

}

Frequently, the ServiceDependency attribute is used for the arguments in a constructor. This means that ObjectBuilder will instantiate the required services when it creates the dependent object.
public class ElectronicFundsTransferController
{
private IAccountServices _accountServices;
public ElectronicFundsTransferController( [ServiceDependency] IAccountServices accountServices )

{
_accountServices = accountServices;
}
...
}

Registering a Service.
To programmatically register a service, call the Add method or AddNew method of the Services collection of the WorkItem within which you want to use the service.


moduleWorkItem.Services.AddNew<AccountServices, IAccountServices>();


Registering a Constructor.
A class can contain more than one constructor. ObjectBuilder first looks for any constructor decorated with the [InjectionConstructor] attribute.
public class CustomersListViewPresenter
{


private CustomersController _controller;

[InjectionConstructor]

public CustomersListViewPresenter ( [ServiceDependency] CustomersController controller )

{
_controller = controller;
}
...
}

Tuesday, May 22, 2007

The Disconnected Service Agent Application Block

Provides management features for executing Web services from occasionally connected smart client applications.
Application can maintain a queue of Web service requests when offline (disconnected) and then replay them when a connection to the server application becomes available.

RequestManager
class manages the request queues and uses the services of the RequestDispatcher class to dispatch these requests. stores the queues of pending and failed requests in a SQL Server 2005 Compact Edition database. It takes the messages from the queue and dispatches them when the application is online. Requests remain in the database until successful submission to the remote server or until the request expires.

Request
class is the store for a Web service request, including the arguments or parameters required by the Web service method.

ConnectionMonitorAdapter
class provides information about the connection used by the request, such as the price and network details, and it raises events when status of the connection changes.

EndpointCatalog
class that contains the endpoints to use for the request. Requests to a remote service require details of the endpoint, such as the network type, credentials, and URL.

OfflineBehavior

class exposes properties that provide information about the request, such as the date and time it was queued. You also use this class to specify features of the request, such as the expiration, maximum number of retries, the number of "stamps", and the Tag value.

Creating Connections and Networks

To create a new connection instance, call the constructor of the appropriate concrete class and specify the name and the price for this connection.
// Create a new NicConnection instance.
NicConnection conn = new NicConnection("NicConnection", 6);
Use the Add method of the ConnectionCollection class
// Add it to the ConnectionMonitor Connections collection.
sampleMonitor.Connections.Add(conn);

You can also use the other methods of the KeyedCollection and Collection classes (from which the ConnectionCollection class inherits) to check for the presence of a specific connection, get a reference to it, and remove it from the ConnectionCollection.

// See if a connection named Internet exists.
if (sampleMonitor.Connections.Contains("Internet"))
{
// Check the connection status.
Connection conn = sampleMonitor.Connections["Internet"];
if (!conn.IsConnected)
{
// Display the price and remove it from the Connections collection.
MessageBox.Show("Removing connection with price "
+ conn.Price.ToString());
sampleMonitor.Connections.Remove(conn);
}
}
The same principles apply to the Network and NetworkCollection classes. You create a new Network instance by specifying the name in a call to the constructor.
Network network = new Network("Intranet", "http://intranet");
Then you add it to the NetworkCollection using the Add method.
sampleMonitor.Networks.Add(network);
You also use the same methods and properties of the underlying KeyedCollection and Collection classes to manipulate the collection of Network instances.
// See if a network named Internet exists.
if (sampleMonitor.Networks.Contains("Intranet"))
{
// Check connection status.
Network netwk = sampleMonitor.Networks["Intranet"];
if (!netwk.Connected)
{
// Remove the network from the Networks collection.
sampleMonitor.Networks.Remove(netwk);
}
}