Infragistics CAB Application Demo: Client Services … using rich user interface components included in NetAdvantage and NCEK. First, let’s take a look at the ClientServicesDesktop
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Infragistics CAB Application Demo: Client Services Desktop This document will describe how the Client Services Desktop application, or simply CSD, is designed and how it works. First off, CSD is created using Microsoft CAB (Composite UI Application Block) as well as Infragistics CAB Extensibility Kit, or NCEK. NCEK contains Workspaces that wrap existing Infragistics elements as well as additional support for UIElement Adapters. NetAdvantage-specific workspaces include:
• DockWorkspace - Based on the NetAdvantage DockManager, this workspace provides docking support for smart parts. The associated DockSmartPartInfo can be used to provide hints about the preferred group to which the pane will be added, as well as the default location and pane style of the group if the preferred group does not exist.
• • ExplorerBarWorkspace - This workspace is based on the NetAdvantage ExplorerBar and
provides support for displaying smart parts within controlcontainer style groups. The associated smart part type is ExplorerBarSmartPartInfo, but no specific properties other than the header image are currently exposed.
• MdiTabWorkspace - Based on the NetAdvantage TabbedMdiManager, this workspace
provides support for displaying smart parts within MDI children that are shown using a tabbed document interface. The associated MdiTabSmartPartInfo class can be used to provide hints about the name of the group to which the MDI child should be associated.
• TabWorkspace - The NetAdvantage TabControl-based workspace provides support for displaying smart parts within tabs. The associated TabSmartPartInfo allows you to choose the image to be displayed within the tab, as well as whether or not the tab should be automatically activated when shown.
• ToolbarsManagerWorkspace - This workspace is based on the NetAdvantage
ToolbarsManager and provides support for displaying smart parts within task panes in the ToolbarsManager. The associated ToolbarsSmartPartInfo can be used to provide hints about the preferred taskpane toolbar such as where the task pane will be displayed, as well as, the default docked position for the taskpanetoolbar if the preferred toolbar does not exist.
The UIElementManager provides a common method of adding to, and using UIElements (e.g., menu items or status bars) in, the shell, such that the developer of an individual piece of business
The CSD application uses a variety of the workspaces and UIElementManagers in NCEK. The remainder of this paper discusses the implementation of CSD.
Inside CSD The CSD application was designed to demonstrate various aspects of implementing CAB applications using rich user interface components included in NetAdvantage and NCEK. First, let’s take a look at the ClientServicesDesktop solution:
Notice how we have several projects. Each of these projects can be referred to as modules. Each module either represents supporting logic and code that is required through out the application or it can represent an add-in to support a particular type of user. The CSD application was designed to be scaled to handle different kinds of users and different kinds of use cases without needing to rebuild and redeploy everything. The CSD.Shell module is the main user interface for this application and it has been designed to contain a main shell. The shell is loaded and it contains one main deck workspace.
When the shell is first loaded, the elements from the CSD.Main module are automatically loaded so that a Login screen is presented to the user.
When attempting to log into the application, if a valid user is retrieved, a check is performed to determine the user type. Depending on the user’s type, a decision is made to load the appropriate smart parts into the shell. Currently for example purposes, CSD uses a simple means to make this determination with the following code: public void StartUserSession(ClientServicesDesktopDataSet.AppUserRow theLoggedInUser) { this.RootWorkItem.State["AppUser"] = theLoggedInUser; switch (theLoggedInUser.UserTypeID) { case 1: //Branch Manager //TODO: future support for this user
break; case 2: //Financial Advisor this.WorkItems.AddNew<FinancialAdvMainWorkItem>().Run(); break; case 3: //Service Rep this.WorkItems.AddNew<ServiceRepMainWorkItem>().Run(); break; } } For future improvement, rather than hard coding this logic as you see here, a better way to do this is to dynamically load the Work Items using reflection and using type info from either an XML File or from a Database. The Root Work Item stores the currently logged in “App User” in its state so that it can be accessed through out the application as needed. If the user happens to be of type “Financial Advisor” the Financial Advisor Main work item is launched. Note: The login name is MIKEL with a password of 12345 Reviewing the code below, we see that on the OnRunStarted method of the work item, we show smart parts as well as register an UltraToolBar as a known site and then add UIElements to it. We then wire the UltraToolBar Tools to command handlers. protected override void OnRunStarted() { base.OnRunStarted(); //create and show the smart part: _financialAdvMainView = this.SmartParts.AddNew<FinancialAdvMainView>(); this.Workspaces[Constants.RootWorkspace].Show(_financialAdvMainView); //register the Toolbar as a known site: this.UIExtensionSites.RegisterSite("FACommandToolBar", _financialAdvMainView.FAToolBarWorkspace.Toolbars["Commands"]); _print.SharedProps.Caption = "Print My Clients"; _print.SharedProps.AppearancesSmall.Appearance.Image = CSD.FinancialAdvisor.Properties.Resources.Printers2.ToBitmap(); this.UIExtensionSites["FACommandToolBar"].Add(_print); this.Commands["PrintCustomerListCommand"].AddInvoker(_print, "ToolClick"); //Now we can load the FA's Home Work Item this.ShowHomeWorkItem(); } The FA Main work item contains methods that are responsible for loading the various use cases (Work Items) related to the Financial Advisor. Such use cases that have been implemented are: Working with Client information, searching for clients, performing client based transactions as well as several others. Each of these are implemented through individual work items. The “Load Client work item” method makes use of a simple pattern: public void LoadClientWorkItem(ClientServicesDesktopDataSet.ClientRow theClient) { ClientMainWorkItem theClientMainWorkItem =
this.WorkItems.Get<ClientMainWorkItem>(theClient.ClientID.ToString()); if (theClientMainWorkItem == null) { theClientMainWorkItem = this.WorkItems.AddNew<ClientMainWorkItem>(theClient.ClientID.ToString()); theClientMainWorkItem.State["Client"] = theClient; theClientMainWorkItem.Run(); //Run for the first time } theClientMainWorkItem.Activate(); //then activate it } Basically, a Client object is used (retrieved from a view such as the UltraWinGrid) in an attempt to locate an existing instance of the “ClientMainWorkItem” and if it is not found, then one is created. The Client object is added to the work item’s state so that it can be accessed within as needed and then the work item is launched. This pattern allows one to load different instances of Clients within this use case.
Using the Infragistics Workspaces adds a new level of power, usability and functionality to your application. One example is by using the UltraDockManager Workspace, smart parts are loaded and represented as dockable panes that can be customized by the end user:
Hints can be provided to the Infragistics workspaces through the use of the appropriate SmartPartInfo implementations. The UltraDockManager workspace makes use of the
UltraDockSmartPartInfo component. Hints that dictate the Dock position and location, Icon, Title and Style can be provided. In this implementation, the component is placed on the Smart Part directly and several properties are set:
An image icon is provided so that when the Tab Groups are created, the icon will appear as follows:
Information that is required at runtime such as the current Client name is retrieved through the Controller and then supplied to the SmartPartInfo’s Title property. This logic is executed directly in the property set assignment inside the ClientMainView: [CreateNew] public ClientMainController Controller { set { _controller = value; this.ultraDockSmartPartInfo1.Title = _controller.CurrentClientContext.LastName + ", " + s_controller.CurrentClientContext.FirstName; } } The Trade use case is initiated by showing the “Trades” tab and then selecting an account to associate the trade with.
Selecting the account from the list and clicking on the round button causes the current holdings for that account to be loaded.
At this point, the end user can either buy or sell shares of existing stocks or buy a new stock that is not currently owned. Clicking on either “buy” or “sell” from the user interface will cause the “buy” or “sell” smart part to be shown so that the end user can complete the transaction.
Once the transaction is complete an event is published and handled to update the view. The data is refreshed to include the changes that resulted from the buy or sell.
The controller contains methods to raise various events. In the case of the Stock Transaction View, the Stock Transaction Controller is used to raise events related to its use case. When the end user performs the stock transaction, the event is raised through the controller: protected void onStockTransactionPerformed(StockTransactionCompleteEventArgs e) { if (StockTransactionComplete != null) { StockTransactionComplete(this, e); } } public class StockTransactionCompleteEventArgs : EventArgs
{ public Enums.TransactionType TransactionType; public int Quantity; public ClientServicesDesktopDataSet.ClientRow Client; public ClientServicesDesktopDataSet.TransactionRow Transaction; public ClientServicesDesktopDataSet.StockRow Stock; public StockTransactionCompleteEventArgs () { } } Basically, the events are published using CAB and the appropriate event arguments are passed as well. The event arguments contain information that can be used if needed to update other elements in the application. In this case, the elements that need to know about the Stock Transaction Complete event subscribe to it and take the appropriate action. Event arguments can be used or ignored depending on the scenario: [EventSubscription("event://StockTransactionComplete", Thread = ThreadOption.UserInterface)] public void StockTransactionComplete(object Sender, StockTransactionCompleteEventArgs e) { this.LoadData(_controller.CurrentAccountTypeContext.AccountTypeID); } Through out this application, a common set of functionality and properties were needed. CSD implements the use of a base user control that contains logic and properties that are needed for all Smart Parts used in this application. The base control is called “CabUserControl” [SmartPart] public partial class CabUserControl : UserControl { public CabUserControl() { InitializeComponent(); this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); } //TOMP: Added this so that all smart parts can be cast to this and access its work item. private WorkItem _theCurrentWorkItem = null; [ServiceDependency] public WorkItem WorkItem { get { return _theCurrentWorkItem; } set { _theCurrentWorkItem = value; } } } This control is designed for optimized painting and it also contains a WorkItem property that can be used and referenced through out the application when needed. The Work Item property is assigned to by CAB through the use of the object builder. One case where the Work Item can be accessed conveniently is for activation. Sometimes when we click on a UI element, we would like the entire Work Item to be activated. The Work Item should be designed so that the onActivated
event is overridden and handled so that certain actions take place. Actions can include the showing of the smart parts that are related to that Work Item. One place where this is used is in the Financial Advisor Main View Smart Part: private void FAMainWorkspace_PaneActivate(object sender, Infragistics.Win.UltraWinDock.ControlPaneEventArgs e) { if (e.Pane.Control is CabUserControl) { ((CabUserControl)e.Pane.Control).WorkItem.Activate(); } } private void FAMainWorkspace_PaneDeactivate(object sender, Infragistics.Win.UltraWinDock.ControlPaneEventArgs e) { if ( e.Pane.Control is CabUserControl && ((CabUserControl)e.Pane.Control).WorkItem.Status == WorkItemStatus.Active ) { System.Diagnostics.Debug.WriteLine("FAMainWorkspace_PaneDeactivate"); ((CabUserControl)e.Pane.Control).WorkItem.Deactivate(); } } Whenever the UltraDockManagerWorkspace’s PaneActivate event fires, the control that is available through the event argument is tested to see if it implements CabUserControl and if it does, we cast it so that we can access its members and then we activate its Work Item. The same is performed for Deactivation, however, the Work Item’s “Status” property must also be tested to make sure that it has not been terminated at this time. In the case of the Client Main Work Item, activation is used to show the Client’s Main View (Smart Part) as well as the dynamically created UltraToolBar tools that allow the end user to Print and Export Client information: protected override void OnActivated() { base.OnActivated(); this.Workspaces[Constants.FAMainWorkspace].Activate(_theClientMainView); this.ShowUiElements(true); } The deactivation hides the UltraToolBarTools so that when another Smart Part is focused, the user interface is not cluttered with controls that do not make sense during the current state of smart part activation. protected override void OnDeactivated() { base.OnDeactivated();
this.ShowUiElements(false); } Each Client Main Work Item contains its own set of UIElements that expose commands to the end user. These UIElements are shown in the UltraToolBar that has been registered with the UI Extension Sites. Closing or Disposing of Work Items was handled by providing the user with a button to explicitly close it.
Whenever the Close button is clicked, the View’s controller is used to dispose the current Work Item: public void CloseWorkItem() { this.WorkItem.Dispose(); } Logic can also be applied to allow the user to receive a prompt before a Work Item is disposed. An interface with a property “Can Close” can be created and implemented by any Work Item that should provide a prompt for users. This can be useful in the event an end user makes changes or “dirties” a record and then attempts to close the form without saving changes.
Appendix A: This appendix lists the Client Services Desktop Smart Part listing. Subsequent versions of this document will contain additional information.
This is the smart part used in the Service Rep use case when working with the Client’s Account information.
This Smart Part is used to build the Account Details View Smart Part.
This Smart Part shows some basic Client information.
Whenever completing a phase of Adding or Editing Client information, this view shows the current phase that you are on. In other words, when you are on the Personal Info part of the data entry, the “Personal Info” icon will change color.
This Smart Part contains other child Smart Parts which when combined allow the end user to edit all Client information.
This View shows all of a particular user’s Clients. If logged in as Michael Lang, Mike will get to see all of his customers in this Smart Part.
This Smart Part is designed to show a list of Clients that are in the system based on filter type data. In other words, this Smart Part is used as a part of a more elaborate view in which the end user types in various data such as a Last Name, Date of Birth and when processed, this view shows any record that meets that criteria.
This view is used as the filter criteria / Data Entry for the Client Grid View Smart Part.
This Smart Part shows a particular Client’s information regarding personal information, account history as well as provides a mechanism to perform transactions (buy / sell stocks)
This view allows the end user to perform transactions with a Client. This Smart Part is used in conjunction with the
This is the root Smart Part for the Financial Advisor. When a user logs into the application, one of several “Root” smart parts will be loaded. In the case of a Financial Advisor, this one will be loaded. Subsequent Smart Parts and Use Cases will be loaded into the workspaces located on this view.
This View is used to plot Market Watch data for the Financial Advisor.
The same concept of a Root Smart Part applies to this one as well. This is the root Smart Part used for the Service Rep.
The main shell of Client Services Desktop is a standard form with a deck workspace. The Login Smart Part is loaded when the app runs. Depending on the person that logs in, subsequent root smart parts are then loaded into the deck.