This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies.
The BankTeller QuickStart is a sample solution inspired by a financial services scenario. It shows a simple customer management application used by an office clerk to interact with customers. It demonstrates all the key Composite UI Application Block features used together in one application.
To run the BankTeller QuickStart
- Open the BankTeller QuickStartsolution in Visual Studio 2008.
- On the Build menu, click Rebuild Solution.
- Click the Start Debugging button on the standard toolbar, or click Start Debugging on the Debug menu.
This is the most complex of the QuickStart examples, and provides an application that more closely resembles that of a real-world scenario. As such, it uses many of the features demonstrated in the previous QuickStarts, combining them with the principles shown in the Walkthrough example and the techniques described in the Design and Development sections of the Composite UI Application Block documentation.
The BankTeller has a single main shell window that presents an empty list when first loaded, as shown in Figure 1. If you imagine a bank worker who is presented with this is one of a number of such employees, the first task is to collect the next customer that requires processing from the queue of customers held in a database or other external service (although, in this example, the customers are hard-coded in the application).
Accepting a customer in the BankTeller QuickStart
On accepting the next customer from the queue, this customer appears in the list. The bank worker then clicks on this customer, which loads their information and displays it in the right window in a tabbed workspace. The first two tabs show the customer details and a list of their accounts (see Figure 2).
Displaying customer details in the BankTeller QuickStart
The third tab, Customer Map, demonstrates how you can extend a Composite UI Application Block application without being required to rewrite or adapt existing code. A WorkItemExtension included with the application is loaded automatically as the application runs.
This is a separate module, and contains the WorkItem, the controller, and the view that—together—implement the Customer Map SmartPart and its business logic. As it loads, the Customer Map SmartPart accesses the MSN Maps Web site and displays a map of the customer's location using the address data that is part of the shared state. Figure 3 shows the result.
The CustomerMap SmartPart displayed on the BankShell form.
The Summary tab contains a Comments button that opens another page in the right tabbed window section of the shell, as shown in Figure 4.
Clicking the Comments button loads and displays the Comments SmartPart
Other features of this example allow you to save the changes you make to each customer (in this case, using the IsolatedStorageStatePersistenceServiceto create or update a file on disk). You can also use the commands on the menu strip to carry out many of the actions within the application.
What You Need to Know
To understand this example, you should be familiar with the following:
- The Model-View-Controller design pattern
- The basic principles of the design of the Composite UI Application Block framework
- The techniques demonstrated in the previous QuickStarts
- The terms listed in the Glossary of Terms section
Design of the BankTeller QuickStart
The BankTeller QuickStart contains several SmartParts, some of which are loaded as the application starts and some that are loaded dynamically in code as it runs. Figure 5 shows the shell form, container controls, all the SmartParts that are used, and their location and nesting within each other.
The SmartParts and container controls used in the BankTeller example
The following steps describe the startup sequence of the example:
- The Main method in BankShellApplication.cs creates an instance of the shell application class and calls its Run method. The FormShellApplication declaration specifies the default root WorkItem, and the BankShellForm as the shell form.
- During the initialization process, the ModuleLoaderService loads the BankTellerModule.dll module and the CustomerMapExtensionModule.dll listed in ProfileCatalog.xml.
- The BankShellApplication class overrides the AfterShellCreated method to get a reference to the File menu item added to the mainMenuStrip at the top of the BankShellForm form at design time. It registers this with the UIExtensionSites collection of the root WorkItem as a site for the addition of other menu items at run time using the RegisterSite method. It also registers as sites the mainMenuStrip itself, the mainStatusStrip at the bottom of the BankShellForm form, and the drop-down section of the File menu.
- The AfterShellCreated method then calls the LoadFromConfig method in the file UIElementBuilder.cs, which reads details of the remaining menu items from the <shellitems> section of the App.Config file. For each one, it creates the new menu item, adds it to the specified site by accessing the specific UIExtensionSite within the UIExtensionSites collection of the root WorkItem. It then uses the name of the command specified in the configuration file to get the Command object from the Commands collection of the MainWorkItem, and registers the Click event with this Command object using the AddInvoker method.
- The BankTellerModuleInit class in the BankTellerModule uses the [InjectionConstructor] attribute on its constructor, together with a [ServiceDependency] attribute, to get a reference to the root WorkItem.
- The Load method in theBankTellerModuleInit class calls the AddCustomerMenuItem routine to create a top-level Customer menu item, add it to the main menu strip, and register a site for its drop-down collection for the later addition of other menu items.
- The Load method then gets references to the two workspaces (the left customer list and the right area that will display a TabWorkspace control) from the Workspaces collection of the root WorkItem. Finally, it creates a new child BankTellerWorkItem within the context of the root WorkItem using the AddNew method, and calls the Show method of the BankTellerWorkItem.
- The Show method of the BankTellerWorkItem creates an instance of the UserInfoSmartPart, and an instance of the SideBarViewSmartPart that contains a SmartPartPlaceholder where the UserInfoSmartPart will display. Then it calls a separate routine in the BankTellerWorkItem called AddMenuItems.
- The AddMenuItems routine checks to see if the main menu strip in the BankShellForm window already contains a top-level Queue menu item. If not, it creates a new menu item, adds it to the main menu, and registers its drop-down collection as a site for the later addition of other menu items. Then it creates a new menu item named AcceptCustomer with a shortcut key combination Ctrl-A, and adds this to the Queue menu. Finally, it accesses an existing Command, or a new one if there is not one already present (the Get method does this automatically), and registers the Click event of the menu item with this Command.
- The Show method of the BankTellerWorkItem now shows the SideBarViewSmartPart and its contained UserInfoSmartPart in the DeckWorkspace named sideBarWorkspace, located in the left panel of the SplitContainer control on the BankShellForm.
- The final line of code in the Show method of the BankTellerWorkItem activates this WorkItem. By overriding the OnActivated method, it makes the Queue item visible by setting its own ShowQueueMenu property—which sets the Visible property of the Queue item to true.
- The constructor of the UserInfoViewSmartPart accesses the CurrentPrincipal property of the current thread and displays the name of the user.
- The SideBarViewSmartPart contains an instance of the CustomerQueueViewSmartPart (added at design time) that itself contains the AcceptCustomer button and a ListBox to show the list of customers as they are accepted. The CustomerQueueViewSmartPart has a dependency on the CustomerQueueController through the [CreateNew] attribute on the property named MyController, which will cause a new instance of the controller for this view to be created when this when the instance of view is created.
You can interact with the application in several ways:
- Click Accept Customer to retrieve the next customer in the queue.
- Select a user in the list to view their summary details. The Accounts tab shows the customer's accounts and balances, and the Customer Map tab shows an MSN map view of their address.
- Click the Comments button on the Summary tab to view comments for that customer.
- Edit and save data on the Summary and Comments tabs.
The following steps describe the processes that take place when you click the Accept Customer button:
- Clicking the Accept Customer button, or selecting Accept Customer from the Queue menu, executes the OnAcceptCustomer event handler in the CustomerQueueView SmartPart. This event handler is decorated with the [CommandHandler] attribute that links it to the Accept Customer menu item.
- The OnAcceptCustomer event handler calls the GetNextCustomerInQueue method of the CustomerQueueController. This calls the GetNext method of the CustomerQueueService that is instantiated through a [ServiceDependency] attribute.
- The GetNext method of the CustomerQueueService returns a new Customer object, which the CustomerQueueView adds to its list box (see Figure 8 earlier in this section).
The following steps describe the processes that take place when you select a customer:
- Selecting a customer in the list box executes the OnCustomerSelectionChanged event handler in the CustomerQueueView SmartPart. This event handler calls the WorkWithCustomer method of the CustomerQueueController, passing to it the selected customer.
- The WorkWithCustomer method of the CustomerQueueController calls the WorkWithCustomer method of the BankTellerWorkItem, again passing to it the selected customer.
- The WorkWithCustomer method of the BankTellerWorkItem creates a key based on the ID of the selected customer, and tries to get a reference to an existing child CustomerWorkItem with this key using the Get method of the Items collection of the BankTellerWorkItem.
- If there is no existing matching CustomerWorkItem, the WorkWithCustomer method creates a new child CustomerWorkItem with the specified key, sets the ID property of the new CustomerWorkItem to this key, and adds the customer to the State of the new CustomerWorkItem with this "Customer#[key]" as the identifier key.
- Next, the WorkWithCustomer method references its own property named PersistenceService. This property uses the Get method of the Services collection of the BankTellerWorkItem to get a reference to the FileStatePersistenceService that is added to the root WorkItem at start up—because it is specified in the <services> section of the App.config file. It uses the FileStatePersistenceService to load any existing saved state for this customer from disk.
- The WorkWithCustomer method ends by calling the Show method of the new CustomerWorkItem and passing to it the DeckWorkspace present in the in the right section of the BankShellForm.
- The Show method of the CustomerWorkItem creates a new instance, or retrieves any existing instance, of the CustomerSummaryView and displays it in the DeckWorkspace in the right section of the BankShellForm.
- The Show method also calls a routine named AddMenuItems that checks if the Customer menu already contains an Edit item. If not, it creates a new Edit menu item, adds it to the Customer menu, and links the Click event to the EditCustomercommand. It also links the MouseHover event for the CustomerSummaryViewSmartPart to the CustomerMouseOvercommand (all the constants used in the application are declared in the BankTellerConstants.cs file.
- Next, the Show method collects the details of the customer stored in the State of the CustomerWorkItem and raises the UpdateStatusTextEvent event declared at the start of the CustomerWorkItem.cs class file. This event is decorated with the EventPublication attribute with topic name "topic://BankShell/statusupdate", and is of global scope. The Show method creates a string containing the customer's last and first name as the arguments for this event.
- The Show method now calls another routine named UpdateUserAddressLabel that creates a new ToolStripStatusLabel and adds it to the status bar at the bottom of the main window. Then it displays the customer's address in this label.
- The final two statements in the Show method activate this WorkItem, and call the FocusFirstTab routine in the CustomerSummaryViewSmartPart to set the TabWorkspace control to show the first (Summary) tab.
- The CustomerSummaryViewSmartPart contains an instance of the CustomerHeaderView, CustomerDetailView, and CustomerAccountsViewSmartParts, inserted into pages in the TabWorkspace at design time.
- The CustomerHeaderViewSmartPart uses the [State] attribute to obtain the customer details from the WorkItem state. It handles its own Load event to display details of this customer in the text boxes.
- The CustomerDetailViewSmartPart uses the [ServiceDependency] attribute to get a reference to the parent CustomerWorkItem, the [CreateNew] attribute to instantiate an instance of the CustomerDetailController, and the [State] attribute to obtain the customer details from the WorkItem state. It also overrides the OnLoad method to display details of the customer in the text boxes (see Figure 9 earlier in this section).
- The CustomerAccountsViewSmartPart uses the [ServiceDependency] attribute to get a reference to the CustomerAccountsService, and the [State] attribute to obtain the customer details from the WorkItem state. It handles its own Load event to call the GetByCustomerID method of theCustomerAccountsService to get a list of accounts for this customer, and displays these in its DataGridView control.
- The third tab in the right panel, Customer Map, shows a view from the MSN Maps Web site for this customer's address (see Figure 10 earlier in this section). The module CustomerMapExtensionModule.dll containing this SmartPart and theCustomerWorkItemExtension class loads when the application starts because it is listed in the ProfileCatalog.xml file.
- The CustomerWorkItemExtension overrides the OnActivated method of the WorkItemExtension class, which is called when the CustomerWorkItem is activated. In this method, it checks to see if the CustomerMapSmartPart is loaded and, if not, creates a new instance and adds it to the Items collection of the CustomerWorkItem. Then is creates a new TabSmartPartInfo instance, sets the Title property to "Customer Map" (for the text on the tab) and the Description (for the tool-tip), then shows the CustomerMapSmartPart in the TabWorkspace.
- The CustomerMapSmartPart uses the [State] attribute to obtain a reference to the customer information in the CustomerWorkItem, overrides the OnVisibleChanged method to load and display the map for the customer's location.
After a customer name displays, the user interface responds to three events:
- The CustomerSummaryController contains an event handler named OnCustomerEdit. This is decorated with the attribute [CommandHandler(CommandConstants.EDIT_CUSTOMER)], and so executes when the Edit menu item is clicked. This event handler sets the SelectedIndex of the TabWorkspace to zero, which displays the Summary page where the customer's information is available for editing.
- The CustomerWorkItem contains an event handler also named OnCustomerEdit. However, this is decorated with the attribute [CommandHandler(CommandConstants.CUSTOMER_MOUSEOVER)], and so executes when the user moves the mouse pointer over the CustomerSummaryViewSmartPart. This event handler checks if the Status property of this WorkItem is Active, and—if it is—displays a ToolTip over the parent form indicating the ID of the customer being edited.
- The BankShellForm subscribes to the global "status changed" event topic named topic://BankShell/statusupdate event, which is raised when the Show method of the CustomerWorkItem displays a customer. The BankShellForm specifies that the handler will run on the user interface thread, and—in the handler—places the string message sent in the event arguments (the customer name) in the label on the status strip at the bottom of the main window.
The following steps describe the processes that take place when you click the Comments button:
- The CustomerDetailView handles a click on its Comments button with the OnShowComments event handler. This executes the ShowCustomerComments method of the CustomerDetailController.
- The ShowCustomerComments method of the CustomerDetailController executes theShowCustomerComments method of the CustomerWorkItem. This method uses a separate routine that creates a new instance of the CustomerCommentsViewSmartPart, a new TabSmartPartInfo instance with the Title property to "Comments" (for the text on the tab), and then registers the TabSmartPartInfo and the CustomerCommentsView with the WorkItem using the RegisterSmartPartInfo method.
- The ShowCustomerComments method then gets a reference to the TabWorkspace on the CustomerSummaryView, and shows the CustomerCommentsViewSmartPart as a new tab page in that workspace.
The following steps describe the processes that take place when you click the Save button:
- The CustomerSummaryViewSmartPart contains the OnSave event handler that handles the Click event of the Save button and calls the Save method of the CustomerSummaryController.
- The Save method of the CustomerSummaryControllercalls the Save method of the base WorkItem class.
Reviewing the BankTeller QuickStart
The following procedure describes how to review the execution of the BankTeller QuickStart. In this example, you concentrate on the way that the SmartParts are loaded and interact. To see how modules are loaded, and how to menus and commands are added to the interface, you should review the other more basic QuickStart examples first.
To review the BankTeller QuickStart
- Open the BankTeller QuickStartsolution from the root folder where you installed the Composite UI Application Block files into Visual Studio 2008.
- On the Build menu, click Rebuild Solution.
- Insert breakpoints on the following lines of code:
The second line in the Load method in BankTellerModuleInit.cs
The first line of the OnAcceptCustomermethod in CustomerQueueView.cs
The first line of the OnCustomerSelectionChangedmethod in CustomerQueueView.cs
The first line of the OnShowCommentsmethod in CustomerDetailView.cs
The first line of the OnSavemethod in CustomerSummaryView.cs
- On the Debug menu, click Start Debugging.
- When the debugger enters break mode, single step through to see how the code creates and shows the SideBarView and UserInfoSmartParts in the sideBarWorkspace within the left panel of the SplitContainer control on the BankShellForm.
- Click Accept Customer. Step through the code to see how which the controller calls a method in the CustomerQueueService, and adds them to the list in theSideBarView SmartPart.
- Click the customer you just added to the list. Step through the WorkWithCustomer method in the BankTellerWorkItem to see how it creates a new child CustomerWorkItem or retrieves an existing instance. Notice that this method calls the IsolatedStorageStatePersistenceServiceto load the customer details from disk into the State of the WorkItem.
- Continue to step through the code seeing how a call to the Show method in the CustomerWorkItem to display the CustomerSummaryViewSmartPart causes this and all the other SmartParts to load and show their data.
- Click the Comments button in the CustomerSummary tab page. Step through the code in which the controller calls a method in the CustomerWorkItem to display the CustomerCommentsViewSmartPart in the TabWorkspace.
- Edit this comment and click the Save button. Step through the code in which the controller calls a method in the base WorkItem class that uses the IsolatedStorageStatePersistenceServiceto save the updated customer data.