Thursday, May 31, 2007
Action Catalog.
example
An application that shows a view in a workspace only if the current user is associated with a specific role.
The action is the code that shows the view.
The condition is the code that determines the user's role.
Developers register an action catalog as a service.
Endpoint Catalog Application Block
<configSections>
<section name="Endpoints" type="Microsoft.Practices.SmartClient.EndpointCatalog.Configuration.EndpointSection, Microsoft.Practices.SmartClient.EndpointCatalog" />
</configSections>
Create the application block configuration section
<Endpoints>
<EndpointItems>
<add Name="WebService1" Address="http://default-host.com/WebService1.asmx" UserName="default-user-name" Password="default-password" Domain="default-domain">
</add>
</EndpointItems>
</Endpoints>
create a new EndpointCatalog and add it to a WorkItem
using Microsoft.Practices.SmartClient.EndpointCatalog;Getting an Endpoint Catalog Instance from a WorkItem
using System.Net;
// Specify the section name in the configuration file.
IEndpointCatalogFactory catalogFactory = new EndpointCatalogFactory("Endpoints");
IEndpointCatalog catalog = catalogFactory.CreateCatalog();
myWorkItem.Services.Add<IEndpointCatalog>(catalog);
Method 1:
public class MyNewClassMethod 2:
{
private EndpointCatalog catalog;
public MyNewClass([ServiceDependency] EndpointCatalog catalog)
{
this.catalog = catalog;
}
...
}
public class MyNewClassMethod 3:
{
private EndpointCatalog catalog;
[ServiceDependency]
public EndpointCatalog EndpointCatalog
{
get { return this.catalog; }
set { this.catalog = value; }
}
...
}
public class MyNewClass
{
private EndpointCatalog catalog;
public MyNewClass()
{
this.catalog = myWorkItem.Services.Get<EndpointCatalog>();
}
...
}
Listing and Getting Information about Endpoints
To check whether an endpoint exists
String epName = "MyWebServiceEndpoint";
if (catalog.EndpointExists(epName))
{
// Endpoint named MyWebServiceEndpoint does exist in the catalog.
}
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;
}
Endpoint Catalog Application Block - Config
<EndpointItems>
<add Name="WebService1" Address="http://default-host.com/WebService1.asmx" UserName="default-user-name" Password="default-password" Domain="default-domain">
<NetworkItems></add>
<add Name="Internet" Address="http://internet-host.com/WebService1.asmx"
UserName="internet-user-name" Password="internet-password" />
<add Name="Work" Address="http://work-host.com/WebService1.asmx"
UserName="work-user-name" Password="work-password" />
</NetworkItems>
<add Name="WebService2" Address="http://default-host.com/WebService2.asmx" UserName="default-user-name" Password="default-password" Domain="default-domain">
<NetworkItems></add>
<add Name="Internet" Address="http://internet-host.com/WebService2.asmx"
UserName="internet-user-name" Password="internet-password" />
</NetworkItems>
</EndpointItems>
</Endpoints>
Disconnected Service Agent Application Block
Microsoft.Practices.SmartClient.DisconnectedAgent
Microsoft.Practices.SmartClient.EnterpriseLibrary
Initializing the Request Manager
- Invoke any of the two overloads of the static method Initialize.
// for default database that specified in the Data Access Application Block configuration.RequestManager requestManager = DatabaseRequestManagerIntializer.Initialize();
OR
RequestManager requestManager = DatabaseRequestManagerIntializer.Initialize("databaseName"); - To full control over the objects used to initialize the request manager, manually construct the objects and call the Initialize method
- EndpointCatalogFactory catalogFactory = new EndpointCatalogFactory("Endpoints");
catalog = catalogFactory.CreateCatalog();
SmartClientDatabase requestQueueDb = new
SmartClientDatabase(ConfigurationManager.ConnectionStrings["QueueConnectionString"].ConnectionString);
DatabaseRequestQueue requestQueue = new DatabaseRequestQueue(requestQueueDb, "RequestsQueue");
SmartClientDatabase deadLetterQueueDb = new SmartClientDatabase(ConfigurationManager.ConnectionStrings["QueueConnectionString"].ConnectionString);
DatabaseRequestQueue deadLetterQueue = new
DatabaseRequestQueue(deadLetterQueueDb, "DeadLetterQueue");
ConnectionMonitorAdapter adapter = new ConnectionMonitorAdapter(ConnectionMonitorFactory.CreateFromConfiguration());
RequestManager manager = RequestManager.Instance;
manager.Initialize(requestQueue, deadLetterQueue, adapter, catalog);
Creating a Simple Request
Request req = new Request();specify the online proxy type for the request. The proxy class is the one that Visual Studio generates when you add a Web reference to your project.
req.MethodName = "DeliveryRouteUpdate";
req.Endpoint = "MyWebServiceHost";
req.OnlineProxyType = typeof(MyWebServiceProxy);specify the behavior of the request
behavior.ProxyFactoryType = typeof(WebServiceProxyFactory);other OfflineBehavior properties are Tag, MaxRetries, Stamps
Adding Parameters to a Request
int customerCode = 1234;Handling Callbacks for a Request
string comment = "New value for comment";
req.CallParameters = CallParameters.ToArray(customerCode, comment);
req.Behavior.ReturnCallbackmethod that takes references to the Request, an Object array for the parameters (arguments) you submitted to the service, and an Object for any value returned by the Web service.
= new CommandCallback(typeof(MyDisconnectedServiceAgentCallbackClass),
"MyReturnCallbackMethod");
req.Behavior.ExceptionCallback
= new CommandCallback(typeof(MyDisconnectedServiceAgentCallbackClass),
"MyExceptionCallbackMethod");
public void MyReturnCallbackMethod(Request req, Object[] qParams,
Object result)
{
MessageBox.Show("Request succeeded. Return value is: "
+ result.ToString());
}
public OnExceptionAction MyExceptionCallbackMethod(Request req,
Exception ex)
{
MessageBox.Show("Your request failed with error: " + ex.Message);
return OnExceptionAction.Dismiss;
}
Adding a Request to a Queue
requestManager.RequestQueue.Enqueue(req);Removing a Request from a Queue
requestManager.DeadLetterQueue.Remove(req)Accessing Requests in a Queue
IRequestQueue theQueue = requestManager.RequestQueue;
// or:
IRequestQueue theQueue = requestManager.DeadLetterQueue;
// Count the number of requests in the queue.
Int32 queueCount = theQueue.GetCount();
// Get a reference to the next request in the queue.
Request nextRequest = theQueue.GetNextRequest();
// Get all the requests in the queue.
IEnumerable>Request> requests = theQueue.GetRequests();
// Get single request iterator by request ID.
Request requestById = theQueue.GetRequest(requestId);
// Get all the requests that have a specified Tag property value.
IEnumerable>Request> requestsByTag = theQueue.GetRequests("SalesOrder");
// Get all the requests that have a specified "stamps" value
// that is greater than or equal to a specified numerical value.
IEnumerable>Request> requestsByPrice = theQueue.GetRequests(5);
To remove a request from the queue, pass a reference to that request to the Remove method of the queue.
theQueue.Remove(req);Dispatching a Single Request Immediately
requestManager.RequestQueue.Enqueue(req);Dispatching All Pending Requests
requestManager.DispatchRequest(req);
requestManager.DispatchAllPendingRequests();Dispatching Specific Pending Requests
requestManager.DispatchPendingRequestsByTag("Sales Order");Starting and Stopping the Dispatcher Service
if (requestManager.Running)
{
reqManager.StopAutomaticDispatch();
OR
reqManager.StartAutomaticDispatch();
}
Conclustion
RequestManager requestManager = DatabaseRequestManagrerInitializer.Initialize();
Request req = new Request();
req.MethodName = "DeliveryRouteUpdate";
req.EndPoint = "MyWebServiceHost";
req.OnlineProxyType = typeof(MyWebServiceProxy);
behavior.ProxyFactoryType = typeof(WebServiceProxyFactory);
int customerCode =1234;
string comment = "New value for cooment";
req. Callparametars=CallParameters.ToArray(customerCode,Comment);
requestManager.RequestQueue.Enqueue(req);
requestManager.DispatchRequest(req);
Wednesday, May 30, 2007
Connection Monitor Application Block
add a <section> node to the <configSections>
<configSections>To use the Connection manager Application Block,
<section name="ConnectionMonitor" type="Microsoft.Practices.SmartClient.ConnectionMonitor.Configuration.ConnectionSettingsSection, Microsoft.Practices.SmartClient.ConnectionMonitor" />
</configSections>
Add configuration information to the application configuration file.
It defines the logical networks and physical network adapters that you want to monitor.
<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>
Instantiate the ConnectionMonitor service and store it in a WorkItem
Call the static CreateFromConfiguration method of the ConnectionMonitorFactory class.
// 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);
Add the ConnectionMonitor instance to the Services collection of your WorkItem
myWorkItem.Services.Add(sampleMonitor);
if (sampleMonitor.Connections.Contains("Internet"))
{
// Check the connection status.
Connection conn = sampleMonitor.Connections["Internet"];
if (!conn.IsConnected)
{
}
Get a reference to the Connection Monitor service from another class
- use a [ServiceDependency] attribute on a parameter of the class constructor to accept an injected reference
public class MyNewClass
{
private ConnectionMonitor sampleMonitor;
public MyNewClass([ServiceDependency] ConnectionMonitor cm)
{
this.sampleMonitor = cm;
}
...
} - Expose a public property for the ConnectionMonitor
public class MyNewClass
{
private ConnectionMonitor sampleMonitor;
[ServiceDependency]
public ConnectionMonitor ConnectionMonitor
{
get { return this.sampleMonitor; }
set { this.sampleMonitor = value; }
}
...
} - Query the Services collection of the WorkItem to obtain a reference to the service
public class MyNewClass
{
private ConnectionMonitor sampleMonitor;
public MyNewClass();
{
this.sampleMonitor = myWorkItem.Services.Get<ConnectionMonitor>();
}
...
}
Detect and handle changes to networks and connectivity
1. Connect your event handler to the StateChanged event of the Connection or Network
conn.StateChanged += StateChangeHandler;2. Network and the Connection classes both raise a StateChanged event when their state changes.
netwk.StateChanged += StateChangeHandler;
public void StateChangeHandler(object sender, StateChangedEventArgs e)
{
if (e.IsConnected)
{ MessageBox.Show("Now connected"); }
}
3. 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.
Create a new connection instance
// Create a new NicConnection instance.Use the Add method of the ConnectionCollection class
NicConnection conn = new NicConnection("NicConnection", 6);
// Add it to the ConnectionMonitor Connections collection.It can also use the other methods of the KeyedCollection and Collection classes to check for the presence of a specific connection
sampleMonitor.Connections.Add(conn);
// 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);
}
}
Tuesday, May 29, 2007
Stage 4: Creating and Showing the SmartPart
Create a Interface named IMyView.cs in the MyModule project and change as .
public interface IMyViewCreate a SmartPart user control
{
event EventHandler Load;
string Message { get; set; }
}
- add a User Control named MyView.cs
- Drag a Label control.
- Implement the IMyView interface
- add IMyView interface t othe class MyView
public partial class MyView : UserControl, IMyView
- right-click IMyView and click Implement Interface, then click Implement Interface in the fly-out menu.
- modify property for Message in Interface.
public string Massage
{
get { return this.label1.Text;}
set { this.label1.Text = value;}
}
- Create a class named MyPresenter.cs
- add a variable of type IMyView
public class MyPresenter
{
IMyView view; - Create a contructor for the class
public MyPresenter(IMyView view)
{
this.view = view;
view.Load += new EventHandler(view_Load);
} - Create a event handler for the Load event
get a reference to the WorkItemvoid view_Load(object sender, EventArgs e)
{
view.Message = "Hello World from a Module";
}
- Open the MyModuleInit.cs add the following after the myCatalogService declaration.
The variable will contain a reference to the root ShellWorkItemprivate WorkItem parentWorkItem;
[ServiceDependency]
public WorkItem ParentWorkItem
{
set { parentWorkItem = value; }
} - 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
- In MyWorkItem.cs, add
using Microsoft.Practices.CompositeUI.SmartParts;
- Create a public Run method that accepts as a parameter a reference to the TabWorkspace.
public void Run(IWorkspace TabWorkspace)
{
IMyView view = this.Items.AddNew<MyView>();
MyPresenter presenter = new MyPresenter(view);
this.Items.Add(presenter);
TabWorkspace.Show(view);
}
Stage 3: Adding the TabWorkspace
- Drag a SplitContainer control onto the form ShellForm.cs .
- Right-click the Toolbox, click Items..., and then click Browse.....
In the \Src\CS\CompositeUI.WinForms\bin\Debug\ subfolder of the folder where you installed the CAB files, select the file Microsoft.Practices.CompositeUI.WinForms.dll. - Drag a TabWorkspace onto the form and drop it onto the left-hand panel of the SplitContainer control.
Stage 2: Creating and Loading the Module
- Add new Class Library project named MyModule to the existing solution
- In Properties->Build->Output select \bin\Debug folder of ShellApplication project
- Save and reopen then, Properties->Outputpath to ..\ShellApplication\bin\Debug
- Add Reference
Microsoft.Practices.CompositeUI.dll
Microsoft.Practices.CompositeUI.WinForms.dll
Microsoft.Practices.ObjectBuilder.dll - Create a class named MyWorkItem.cs derived from WorItem and include namespace
using Microsoft.Practices.CompositeUI;
public class MyWorkItem : WorkItem
{
} - Add a module Initialiser
- 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
{
} - 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; }
} - 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>();
} - 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
- Create a new Windows Forms application named ShellApplication
- rename Form1.cs to ShellForm.cs
- Add Reference
Microsoft.Practices.CompositeUI.dll
Microsoft.Practices.CompositeUI.WinForms.dll
Microsoft.Practices.ObjectBuilder.dll - create a custom workitem
- create a new class named ShellWorkItem.cs
- Inherit class from WorkItem and include namespace
using Microsoft.Practices.CompositeUI;
public class ShellWorkItem : WorkItem
{
} - modification in program.cs
- rename Program.cs to ShellApplication.cs
- include namespace
using Microsoft.Practices.CompositeUI.WinForms;
- Replace the static class ShellApplication with a public class that inherits from FormShellApplication
public class ShellApplication :
FormShellApplication<shellworkitem,shellform>
{
} [STAThread]
static void Main()
{
new ShellApplication().Run();
}
Basic Commands...
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
- create a class inherit from Microsoft.Practices.CompositeUI.WorkItem.
- 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)steps2: In the child WorkItem, use the State attribute to indicate that a parent WorkItem should inject the property into the child WorkItem.
{
// set state for injection into child WorkItem
State["Customer"] = custmr;
ChildWorkItem myChild = this.WorkItems.AddNew<ChildWorkItem>();
myChild.Run();
}
// 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")]associate a Command with a UIElement
public void ShowName(object sender, EventArgs e)
{
MessageBox.Show("My name is Joe");
}
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))]Services that do not provide different implementations may not implement an interface
public class MyService : IMyService
{
}
[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
- create a new class library or Windows control library project
- add reference to Microsoft.Practices.CompositeUI and Microsoft.Practices.ObjectBuilder
- add a module attribute to identify this as a module.
- [assembly: Microsoft.Practices.CompositeUI.Module("mainMod")] in AssemblyInfo.cs
Create a module Initializer
- create a new public class
- inherit from Microsoft.Practices.CompositeUI.ModuleInit class.
- you can override the AddServices method
- you can override the Load method
put following in either in the ModuleInit or AssemblyInfo.cs
[assembly: Microsoft.Practices.CompositeUI.ModuleDependency(load a module
"TheModuleYouDependOn")]
<?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));declaratively
// or using generics
IMyService myServ = myWorkItem.Services.Get<IMyService>();
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]display a SmartPart in a Workspace
public partial class MySmartPart : UserControl
public class MyWorkItem : WorkItemimplement the MVC pattern
{
protected override void OnRunStarted()
{
base.OnRunStarted();
CustomerSmartPart csp = this.SmartParts.AddNew<CustomerSmartPart>();
Workspaces["tabbedArea"].Show(csp);
}
}
protected override void OnRunStarted()Publishing Events
{
base.OnRunStarted();
SampleView view = this.Items.AddNew<SampleView>();
workspace.Show(view);
}
[EventPublication("event://UpdatesAvailable", PublicationScope.Global)]Subscribing to Events
public event SomeEventHandler UpdatesAvailable;
[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
RootWorkItem.UIExtensionSites.RegisterSite(“FileMenu”, Shell.MainMenuStrip);WorkItems.
ToolStripMenuItem printItem = new ToolStripMenuItem("Print");
RootWorkItem.UIExtensionSites[“FileMenu”].Add(printItem);
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)]subscription
public event EventHandler<DataEventArgs<UpdateData>> UpdatesAvailable;
// or
[EventPublication("topic://UpdatesAvailable", PublicationScope.Global)]
public event EventHandler UpdatesAvailable;
[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
services.<?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>
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.
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
Creating New Objects.
[CreateNew]The CreateNew attribute instructs ObjectBuilder to instantiate and initialize an instance of a NewTransferViewPresenter when the NewTransferView is created.
public NewTransferViewPresenter Presenter
{
get { return _presenter; }
set
{
_presenter = value;
_presenter.View = this;
}
}
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;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.
[ServiceDependency]
public IAccountServices AccountServices
{
set { _accountServices = value; }
}
public class ElectronicFundsTransferControllerRegistering a Service.
{
private IAccountServices _accountServices;
public ElectronicFundsTransferController( [ServiceDependency] IAccountServices accountServices )
{
_accountServices = accountServices;
}
...
}
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
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
// Create a new NicConnection instance.Use the Add method of the ConnectionCollection class
NicConnection conn = new NicConnection("NicConnection", 6);
// 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.
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.
// 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);
}
}
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);
}
}
Monday, May 21, 2007
Handling Connectivity Change Events
The Network and the Connection classes both raise a StateChanged event when their state changes. Create a handler for this event that accepts an instance of the StateChangedEventArgs class, which exposes the IsConnected property
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;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.
netwk.StateChanged += StateChangeHandler;
conn.UpdateStatus();
Listing the Configured Networks
NetworkCollection netList = sampleMonitor.Networks;The NetworkCollection class inherits from the generic collection class KeyedCollection, and implements the IEnumerable interface.
StringBuilder builder = new StringBuilder();To obtain a list of the connected networks only, use the ActiveNetworks property of the NetworkCollection class.
foreach (Network netwk in netList)
{
builder.Append(String.Format("Name: {0}, Connected: {1}",
netwk.Name, netwk.Connected.ToString()));
builder.Append("\n");
}
ReadOnlyCollection<network> activeNetworks = sampleMonitor.Networks.ActiveNetworks;
Get a list of the connections configured in an application
<Connections>You can obtain a list of the configured connections from the Connections property of the ConnectionMonitor.
<add Type="WiredConnection" Price="1" />
<add Type="WirelessConnection" Price="2" />
</Connections>
ConnectionCollection connList = sampleMonitor.Connections;The ConnectionCollection class inherits from the generic collection class KeyedCollection and implements the IEnumerable interface.
StringBuilder builder = new StringBuilder();
foreach (Connection conn in connList)
{
builder.Append(String.Format("Type: {0}, Price: {1}, "
+ "IsConnected: {2}",
conn.ConnectionTypeName,
conn.Price.ToString(),
conn.IsConnected.ToString()));
builder.Append("\n");
}
Referencing the Connection Monitor Service
If you have stored an instance of the ConnectionMonitor class in your WorkItem, you can reference it from any other class within the scope of that WorkItem. You can use a [ServiceDependency] attribute on a parameter of the class constructor to accept an injected reference and store it in a class-level variable.
public class MyNewClassAlternatively, you can expose a public property for the ConnectionMonitor and have ObjectBuilder set it to the ConnectionMonitor instance in the WorkItem.
{
private ConnectionMonitor sampleMonitor;
public MyNewClass([ServiceDependency] ConnectionMonitor cm)
{
this.sampleMonitor = cm;
}
...
}
public class MyNewClassAnother approach is to directly query the Services collection of the WorkItem to obtain a reference to the service you want.
{
private ConnectionMonitor sampleMonitor;
[ServiceDependency]
public ConnectionMonitor ConnectionMonitor
{
get { return this.sampleMonitor; }
set { this.sampleMonitor = value; }
}
...
}
public class MyNewClass
{
private ConnectionMonitor sampleMonitor;
public MyNewClass();
{
this.sampleMonitor = myWorkItem.Services.Get();
}
...
}
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."
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.
// 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);
myWorkItem.Services.Add(sampleMonitor);
Configuring the Connection Monitor Application Block
<ConnectionMonitor>Following values can use for the Type attribute
<Networks>
<add Name="Intranet" Address="http://contoso"/>
<add Name="Internet" Address="http://www.microsoft.com"/>
</Networks>
<Connections>
<add Type="WiredConnection" Price="1"/>
</Connections>
</ConnectionMonitor>
- NicConnection. The application block uses the NicConnection class to monitor any network interface connection—for example, an Ethernet card or wireless adapter. This class provides the capability to detect if the application has a connection to a network.
- WiredConnection. The application block uses the WiredConnection class to monitor connectivity to Ethernet adapters.
- WirelessConnection. The application block uses the WirelessConnection class to monitor connectivity to wireless network adapters.
- DesktopConnection. The application block uses the DesktopConnection class to monitor connectivity to local services (you can manually set the connection state of this class).
Define a configuration section for the application block in the application configuration file. To do this, add a <section> node to the <configSections> node of your App.config file
<configSections>Create the application block configuration section and define your logical networks. Configure each logical network inside a
<section name="ConnectionMonitor" type="Microsoft.Practices.SmartClient.ConnectionMonitor.Configuration.ConnectionSettingsSection, Microsoft.Practices.SmartClient.ConnectionMonitor" />
</configSections>
<ConnectionMonitor>If you want to monitor physical network adapters, add the configuration information for the network adapters inside a <connections> element.
<Networks>
<add Name="Intranet" Address="http://intranet"/>
<add Name="Internet" Address="http://www.microsoft.com"/>
</Networks>
</ConnectionMonitor>
<ConnectionMonitor>Optionally, specify the type name of the network status strategy to use to monitor the connection status of the logical network.
<Connections>
<add Type="WiredConnection" Price="1"/>
<add Type="WirelessConnection" Price="2"/>
</Connections>
</ConnectionMonitor>
<ConnectionMonitor>
<Networks StrategyType="ConnectionModule.CustomNetworkStatusStrategy, ConnectionModule">
<add Name="Intranet" Address="http://intranet"/>
<add Name="Internet" Address="http://www.microsoft.com"/>
</Networks>
</ConnectionMonitor>
Network Monitoring
The ConnectionMonitor class exposes a NetworkCollection instance through its Networks property. The NetworkCollection class inherits from KeyedCollection, exposing a generic list of Network instances keyed by name. This allows you to enumerate the available networks in your application code.
The Network class represents a logical network and exposes the network name and address. It also exposes a Connected property, which your code can use to check for connectivity to a specific network. You can use the StateChanged event to detect changes to the status of the network connection.
Connection Monitoring
- NicConnection. This represents any network interface connection—for example, an Ethernet card or wireless adapter. This class provides the capability to detect if the application has a connection to a network.
The application block also contains two classes that derive from NicConnection. - WiredConnection. This represents a wired connection.
- WirelessConnection. This represents a wireless connection
- DesktopConnection. This represents a local connection. You can use a desktop connection to programmatically updannte its status (connected or discoected).
Introduction to the Connection Monitor Application Block
A logical network is defined by the developer and represents a set of remote resources (for example, Web services).
With the Connection Monitor Application Block, a logical network is a collection of network addresses for a set of resources required by an application.
The following are examples of logical networks:
- The internet
- A corporate or home network
- A virtual private network (VPN)
Contents
- Introducing the Smart Client Software Factory
- Exploring the Smart Client Software Factory
- Scenarios and Benefits
- Software Factory Capabilities
- Composite Smart Client Applications
- Software Factories
- Glossary of Terms
- Inspecting the Software Factory Assets
- Application Blocks
- ObjectBuilder
- Design of ObjectBuilder
- Working with ObjectBuilder
- Composite UI Application Block
- Introduction to the Composite UI Application Block
- Scenarios and Design Goals
- Scenarios and Design Goals
- Introduction to the Composite UI Application Block
- Design of the Composite UI Application Block
- Overall Design Goals
- Design for Modularity
- Design for Productivity
- Design for Extensibility
- Design of Subsystems
- Design of the Application Shell
- Design of the Workitem
- Design of Workspaces
- Design of UIElementAdapters
- Design of Commands
- Design of the Injection Model
- Design of the Services
- Design of the Module Enumerator Service
- Design of the Event Broker Service
- Design of the Module Loader Service
- Design of the Authentication Service
- Design of the State Persistence Service
- Application Initialization Sequence
- Threat Model
- Overall Design Goals
- Developing Applications Using the Composite UI Application Block
- Creating a Shell
- Adding Service
- Creating a Module
- Getting References to Services
- Creating Custom Services
- Creating showing SmartParts
- Developing with the MVC Pattern
- Publishing and subscribing to Events
- Working with WorkItems
- Showing UIElements
- Registering Commands
- Using the visualizer
- Writing Custom Visualizations
- Extending the Composite UI Application Block
- Building Custom Workspaces
- Building Custom UIElementAdapters
- Changing the Initialization Services
- Deployment and Operations
- Deploying the Composite UI Application Block
- Using ClickOnce with Composite UI Application Block
- Walkthrough: Designing and building CAB applications
- Application Requirements and Design
- Developing the Architecture
- Implementing the Appilcation
- Stage 1: Creating the Shell and the Form
- Stage 2: Creating and Loading the Module
- Stage 3: Adding the TabWorkspaces
- Stage 4: Creating and Showing the SmartPart
- Composite UI Application Block Extensions for WPF
- The Connection Monitor Application Block
- Introduction to Connection Monitor Application Block
- Design of the Connection Monitor Application Block
- Working with the Connection Monitor Application Block
- Configuring the Connection Monitor Application Block
- Creating a Connection Monitor instance
- Referencing the Connection Monitor Application Service
- Listing the Configured Connections
- listing the Configured Networks
- Handling Connectivity Change Events
- Creating Connections and Networks
- Extending the Connection Monitor Application Block
- The Disconnected Service Agent Application Block
- Design of the Disconnected Service Agent Application Block
- Working with the Disconnected Service Agent Application Block
- Initializing the Request Manager
- Creating a simple request
- Adding Parameters to a Request
- Handling Callbacks for a Request
- Adding a requests to a Queue
- Removing a Request from a Queue
- Accessing Requests in a Queue
- Dispatching a Single Request Immediately
- Dispatching All Pending Requests
- Dispatching Specific Pending Requests
- Starting anf Stopping the Dispatcher Service
- Web Service Idempotency and WS-Addressing
- Extending the Disconnected Service Agent Application Block
- The Endpoint Catalog Application Block
- Design of the Endpoint Catalog Application Block
- Working with Endpoint Catalog Application Block
- Configuring the Endpoint Catalog Application Block
- Creating an Endpoint Catalog Class Instance
- Getting an Endpoint Catalog Instance from a WorkItem
- Listing and Getting Information about Endpoints
- Extending Endpoint Catalog Application Block
- ObjectBuilder
- Guidance Automation
- Registering the Smart Client Software Developement Package
- Using the Smart Client Software Developement Guidance Package
- Create Smart Client Application Next Steps
- Add Bussiness Module Next steps
- Add Foundational Module Next Steps
- Add View(with presenter) Recipe Next Steps
- Add WPF-View (with presenter) Recipe Next Steps
- Add Disconnected Service agent Receipe Next Steps
- Update Disconnected Service Agent Recipe Next Steps
- Add Event Publication Recipe Next Steps
- Add Event Subscription Recipe Next Steps
- Patterns for Smart Client Applications
- Model-View-Presenter(MVP)
- Container Hierarchy
- View Navigation
- Workspace Hierarchy
- UI Threading
- Module Plug-in
- Action Catalog
- Service Locator
- WorkItem Identity Publication
- Quick Starts
- Composite UI Application Block Quickstarts
- EventBroker QuickStart
- ModuleLoader QuickStart
- SmrtPart QuickStart
- Commands QuickStart
- Bank Teller QuickStart
- Offline Application Blocks QuickStarts
- Connection Monitor QuickStart
- Endpoint Catelog QuickStart
- Disconnected Service Agent QuickStart
- Windows Presentation Foundation Integration QuickStart
- Composite UI Application Block Quickstarts
- Reference implementations
- Global Bank Scenario
- Appraiser Workbench
- Running the Reference Implementations
- Requirements
- Application Features
- Architectural Views
- User Experience View
- Logical view
- Implementation View
- Control flow View
- Deployment View
- Bank Branch Cleint
- Running the Reference Implementation
- Use cases
- Application Features
- Architectural Views
- User Experience View
- Logical view
- Implementation View
- Control flow View
- Deployment View
- Application Blocks
- Development Activities
- How to : Create Smart Client Solutions
- How to : Create Business Module
- How to : Create a Foundational Module
- How to : Add a View with a Presenter
- How to : Add a WPF-View with a Presenter
- How to : Create Disconnected Service Agent
- How to : Consume a Disconnected Service Agent
- How to : Update a Disconnected Service Agent
- How to : Enable a Solution to use WPF Extenstions
- How to : Translate Between Business Entities and Service Entities
- How to : Map Business Entities into User Interface Elements
- How to : Publish Events
- How to : Communicate Between Views
- How to : Use the Action Catalog
- Other Considerations
- Versioning considerations
- Securing Data
- How to : Create Smart Client Solutions
- Deploying Smart Client Applications with ClickOnce
- ClickOnce Publishing Process
- ClockOnce Deployment Architecture
- Deploying for multiple Groups
- Handling High Deployment Server Load
- Implementing a Custom ClickOnce Server File Repository
- Deployment Activities
- How to: Publish an Initial Version of an Application
- How to: Deploy an Initial Version of an Application
- How to: Publish an Updated Version
- How to: Deploy an Updated Version
- How to: Move an Application to a Different Server
- How to: Add On-Demand Programmatic Update
- How to: Publish Different Versions for Different Groups
- How to: Restrict Access Based on User Role
- How to: Apply Updates at a Future Time
- How to: Share Application Files Across Versions
- How to: Implement a Custom ClickOnce Deployment Server File Repository
- Customizing the Smart Client Software Factory
- Extending the Application Blocks
- Modifying the Guidance Package
- Modifying the Documentation
Stage 4: Creating and Showing the SmartPart
- Create an interface for the view and the presenter to communicate
- In MyModule project, add a new Interface named IMyView.cs.
- Add the public keyword to the interface statement.
- declare the two members of this interface as an event named Load and a string property named Message
public interface IMyView
{
event EventHandler Load;
string Message { get; set; }
}
- In MyModule project, add a new Interface named IMyView.cs.
- create a SmartPart User control
- In MyModule project, add a User Control named MyView.cs
- drag a Label control.
- implement the IMyView interface
- In User Control MyView.cs,
Add the IMyView interface to the class declaration
public partial class MyView : UserControl, IMyView - Right-click IMyView and click Implement Interface, then click Implement Interface in the fly-out menu.
- Replace the two throw statements that Visual Studio generates with two statements that get and set the value of the Message property
public string Message
{ get
{ return this.label1.Text; }
set
{ this.label1.Text = value; }
}
- In User Control MyView.cs,
- create the presenter class
- add a class named MyPresenter.cs
- make the class public
- add a variable of type IMyView
public class MyPresenter
{
IMyView view; - Create a constructor for the class
public MyPresenter(IMyView view)
{
this.view = view;
view.Load += new EventHandler(view_Load);
} - e. Create an event handler for the Load event.
void view_Load(object sender, EventArgs e)
{
view.Message = "Hello World from a Module";
}
- get a reference to the WorkItem
- In MyModuleInit.cs add the variable after myCatalogService variable declaration private WorkItem parentWorkItem
- add a public property to the class.
[ServiceDependency]
public WorkItem ParentWorkItem
{
set { parentWorkItem = value; }
} - Modify the Load method that you added during Stage 2.
public override void Load()
{
base.Load();
MyWorkItem myWorkItem = parentWorkItem.WorkItems.AddNew <
MyWorkItem > (); myWorkItem.Run(parentWorkItem.Workspaces["tabWorkspace1"]);
}
- create and show the view
- In MyWorkItem.cs,
using Microsoft.Practices.CompositeUI.SmartParts;
Create a public Run method that accepts as a parameter a reference to the TabWorkspace.
public void Run(IWorkspace TabWorkspace()
{
} - Add statements to the Run method that create a new instance of the MyView MyView view = this.Items.AddNew < MyView >();
MyPresenter presenter = new MyPresenter(view); - 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);
- In MyWorkItem.cs,
Stage 3: Adding the TabWorkspace
- Open the file ShellForm.cs
- drag a SplitContainer control onto the form.
- Right-click the Toolbox, click "Items..." and "Browse..."
- select the file Microsoft.Practices.CompositeUI.WinForms.dll.
- Drag a TabWorkspace onto the left-hand panel of the SplitContainer.
- Set Dock property to Fill.
Stage 2: Creating and Loading the Module
- Add a Class Library project named MyModule in the solution ShellApplication.sln
- Project's outputpath should be \ShellApplication\bin\Debug\
- In Add Reference Select these three DLLs:
Microsoft.Practices.CompositeUI.dll
Microsoft.Practices.CompositeUI.WinForms.dll
Microsoft.Practices.ObjectBuilder.dll - Add a new class named MyWorkItem.cs
using Microsoft.Practices.CompositeUI;
inherits from WorkItem as below
public class MyWorkItem : WorkItem
{} - Add a class named MymoduleInit.cs
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.Services;
using System.Windows.Forms; - inherit from ModuleInit as shown here
public class MyModuleInit : ModuleInit - Add the following variable to reference the WorkItemTypeCatalogService
private IWorkItemTypeCatalogService myCatalogService; - Add the following public property to the class that sets the value of the myCatalogService variable.
[ServiceDependency]
public IWorkItemTypeCatalogService myWorkItemCatalog
{
set { myCatalogService = value; }
} - Override the Load method of the ModuleInit class
public override void Load()
{
base.Load();
myCatalogService.RegisterWorkItem <MyWorkItem>();
}
- inherit from ModuleInit as shown here
- instruct the CAB to load the new module
In the ShellApplication project, open the NewItem dialog box and select XML File. Name it ProfileCatalog.xml.
< ?xml version="1.0" encoding="utf-8" ? >
< SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile" %gt
< Modules >
< ModuleInfo AssemblyFile="MyModule.dll" />
</Modules>
</SolutionProfile> - Save and Run the application
Sunday, May 20, 2007
Stage 1: Creating the Shell and the Form
- create a new application named ShellApplication.sln
- In Add Reference Select these three DLLs:
Microsoft.Practices.CompositeUI.dll
Microsoft.Practices.CompositeUI.WinForms.dll
Microsoft.Practices.ObjectBuilder.dll - Create a form named ShellForm.cs
- Create a WorkItem
- Create a class named ShellWorkItem.cs
using Microsoft.Practices.CompositeUI - ShellWorkItem class inherits from WorkItem as shown
public class ShellWorkItem : WorkItem
{}
- Create a class named ShellWorkItem.cs
- rename the file Program.cs to ShellApplication.cs and open it.
using Microsoft.Practices.CompositeUI.WinForms;- Replace the static class ShellApplication with a public class that inherits from FormShellApplication as below
public class ShellApplication : FormShellApplication < shellworkitem, ShellForm> - Change the static Main method as follows
[STAThread]
static void Main()
{
new ShellApplication().Run();
}
- Replace the static class ShellApplication with a public class that inherits from FormShellApplication as below
- Save and Run the application
Hierachies in Smart Cient Apllications
- WorkSpaces
- UI Extension Sites
- Commands
- Services
WorkItems
- SmartParts
- controllers
- services
- UIElements
- other components
Workspaces
- Window
- Mdi
- Tab
- Deck
- Zone
- menus
- toolbars
- status bars
- progress bars
- sidebars
- action panes
- notification tray
Modules can include:
- SmartParts
- support services
- business logic
- configuration information
Application blocks
- Composite UI application block
- Object Builder
- Connection Manager Application Block
- End Point Catalog Application Block
- Disconnected Service Agent Application Block
Saturday, May 19, 2007
Publishing Events
You can publish events using the EventPublication attribute on an event declaration. This attribute uses two parameters: the event name and the event scope.
The event name is a string that identifies the event, for example, event://UpdatesAvailable. The URI syntax convention is recommended to allow for organized and hierarchical naming. For example, event://UpdatesAvailable/New and event://UpdatesAvailable/Deleted.
Use the PublicationScope enumeration to define the event scope as global, available only to this WorkItem and its descendents, or local to this WorkItem.
To publish an event that is available in all WorkItem instances
- Create the event definition as shown in the following code.
public event SomeEventHandler UpdatesAvailable;
- Add the EventPublication attribute to the definition using the PublicationScope.Global parameter as shown in the following code.
[EventPublication("event://UpdatesAvailable", PublicationScope.Global)]
public event SomeEventHandler UpdatesAvailable;
To publish a event available only to the local and descendant WorkItems
- Create the event definition as shown in the following code.
public event SomeEventHandler UpdatesAvailable;
- Add the EventPublication attribute to the definition using the PublicationScope.Descendants parameter as shown in the following code.
[EventPublication("event://UpdatesAvailable",
PublicationScope.Descendants)]
public event SomeEventHandler UpdatesAvailable;
To publish an event that is available only to the local WorkItem
- Create the event definition as shown in the following code.
public event SomeEventHandler UpdatesAvailable;
- Add the EventPublication attribute to the definition using the PublicationScope.WorkItem parameter as shown in the following code.
[EventPublication("event://UpdatesAvailable", PublicationScope.WorkItem)]
public event SomeEventHandler UpdatesAvailable;
Publishing and Subscribing to Events
SmartParts (or other classes) within that WorkItem can then raise the event or subscribe to the published event.
There are two ways of registering publications or subscriptions for an event:
- Using Attributes: You can use specific attributes as described in the example below to declare .NET events as event publications that will propagate via the event broker system. You then declare methods decorated with the EventSubscription attribute to receive these events in your classes. This is the simplest way of working with events, and provides the same flexibility as the normal programmatic approach—but requires less code. For the attributes to be processed, you must create or add the class instance to the WorkItem.
- Programatically: You 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. This gives flexibility in the placing of event registration and unregistration for publications and subscriptions, but is not required for most common cases. You can also fire topics programmatically in this way, without registering a publisher.
Developing with the MVC Pattern
MVC is a fundamental design pattern for the separation of user interface logic from business logic. The pattern separates the modeling of the application domain, the presentation of the application, and the actions based on user input into three distinct objects:
View - Forms, SmartParts, and user controls play the role of a view
Controllers - classes implement controllers
Model - state and other data takes the form of the model.
To build a controller class
- Create a new class in your application and modify the class declaration to inherit from Microsoft.Practices.CompositeUI.Controller.
- Implement your own methods to control the view.
- 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 shown in the following code.
[State("Customer")]
public Customer customer
{
get { return (Customer)State["Customer"]; }
set { State["Customer"] = value; }
}
To build a view class
- Create a form, SmartPart, or user control to display information to the user.
- Create a class to manage the data displayed in the view. For example, you can create a Customer object that has fields such as firstName and lastName. It is also common to use the DataSet for simpler applications. You can use the State attribute to keep data in a common place within the class.
- Add the [CreateNew] attribute to inject an instance of the dependent class through a property, as shown in the following code.
private MyControllerClass myController;
[CreateNew]
public MyControllerClass Controller
{
set { myController = value; }
}
To implement the MVC pattern
- Create a WorkItemas shown in the following code.
public class MyWorkItem : WorkItem
{
} - Override the OnRunStarted Method of the WorkItem to create an instance of the view, as shown in the following code. This automatically creates or retrieves the corresponding controller instance.
protected override void OnRunStarted()
{
base.OnRunStarted();
SampleView view = this.Items.AddNew();
workspace.Show(view);
}
Creating and Showing SmartParts
There are two scenarios for using SmartParts in a CAB application:
- The SmartPart required for a given location on a form is known at design time.
- The SmartPart is created and displayed dynamically at runtime, typically in response to user interaction.
To create a SmartPart
- Add a user control to your project.
- Add a reference to the Microsoft.Practices.CompositeUI.SmartParts namespace.
- Design the control to provide the appropriate appearance and functionality.
- Add the SmartPart attribute to the control class as shown in the following code.
[SmartPart]
public partial class MySmartPart : UserControl
To display a SmartPart dynamically at runtime, you can either allow a Workspace control to manage the positioning and dimensions of the SmartPart or you can explicitly designate an area in a form where the SmartPart will appear at runtime by using a SmartPartPlaceHolder control.
To display a SmartPart in a SmartPartPlaceholder
- Create an instance of the SmartPart user control using the AddNew method of the SmartParts 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");
To display a SmartPart in a Workspace
- Create an instance of the SmartPart user control with the AddNew method of the SmartParts collection of the WorkItem.
- 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);
}
}
Creating Custom Services
To create a service
- Add a new interface to an appropriate module.
- Add members that the interface will define.
- Add a new class to the module or the shell.
- Inherit from the interface and add the required functionality to the members.
- Add the Service attribute to the class definition as shown in the following code.
[Service(Type=typeof(IMyService))]
public class MyService : IMyService
Getting References to Services
References to services are obtainable either programmatically or declaratively.
I. To obtain a reference to a service programmatically
- Call the Get method of the Services collection of the WorkItem, passing in the type of service as shown in the following code.
II. To obtain a reference to a service declarativelyIMyService myServ = (IMyService)myWorkItem.Services.Get(typeof(IMyService));
// or using generics
IMyService myServ = myWorkItem.Services.Get();
- Add the ServiceDependency attribute to a property in your class that that is of the type of service or interface you require, as shown in the following code.
private IMyService service;
[ServiceDependency]
public IMyService MyService
{
set { service = value; }
}
Creating a Module
A module is a .NET assembly that has attributes, and contains classes that the CAB can find and use.
Dependency affects the loading sequence.
To create a module
- Create a new class library project or Windows control library project.
- Add a reference to Microsoft.Practices.CompositeUI and Microsoft.Practices.ObjectBuilder
- 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")]
To create a module initializer
- Create a new public class in the library project.
- Modify the class to inherit from the Microsoft.Practices.CompositeUI.ModuleInit class.
- If you want to add services programmatically 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.
To add dependencies to the module
- Either in the ModuleInit class or in the AssemblyInfo file, add module dependencies as shown in the following code.
[assembly: Microsoft.Practices.CompositeUI.ModuleDependency("TheModuleYouDependOn")]
To load modules when the application starts, you must use a catalog file to list the modules to load. The default name for this file is ProfileCatalog.xml.
To load a module
- Add a new XML file to the main project named ProfileCatalog.xml.
- Edit the contents of ProfileCatalog.xml to list the appropriate modules to load as shown in the following code.