Prescriptive Architecture
User Interface Process (UIP) Application Block - Version 2.0
 

Patterns and Practices home

Microsoft Corporation

April 2004

Summary: Chapter 3 details the process for building and using the block. The chapter also presents QuickStarts to help you understand the steps that are needed to implement your own UIP solution.

Contents

Preparing to Build the UIP Application Block
Migrating Applications That Use UIP Application Block, Version 1
Developing an Application with the UIP Application Block
QuickStarts for the UIP Application Block
Conclusion

You can use the UIP Application Block to control presentation layer business logic in both Windows-based applications and Web applications. This chapter includes information about developing applications using the provided classes of the UIP Application Block. It shows how to develop the views (Windows Forms or Web pages) that your users interact with, define the path of flow between the views, and develop a controller to coordinate the navigation between views.

This chapter also introduces several QuickStarts that come with the block. The QuickStarts allow you to gain a deeper understanding of the block.

Important   The QuickStarts are intended to aid you in understanding the block; they are not intended to be production-ready code samples and may not be indicative of the way you should develop your application.

The UIP Application Block is designed to be flexible: It is useful without modification, and also gives you the ability to extend its functionality. You can write custom classes in your application to replace standard classes in the block. Appendix A, "Extending the UIP Application Block," provides guidance on developing your own state management class, developing custom state persistence providers, and developing custom view implementations.

Preparing to Build the UIP Application Block

To work with the UIP Application Block, you need to ensure that your system meets the following minimum software requirements:

  • Microsoft® Windows® XP or Windows Server™ 2003 operating system
  • Microsoft .NET Framework version 1.1
  • Microsoft Visual Studio® .NET 2003 Enterprise Architect, Enterprise Developer, or .NET Professional edition development system

These are the minimum requirements for using the block. However, if you are using the block for Web applications, you need Internet Information Services (IIS) version 5.0 or later, and if you are planning to use the SQL Server persistence provider, you need Microsoft SQL Server™ 2000.

Note   Although the UIP Application Block has not been fully tested on Windows 2000, the QuickStarts run on Windows 2000.

Migrating Applications That Use UIP Application Block, Version 1

If you are already using version 1 of the UIP Application Block in an application, you must make a few modifications in your code to ensure that your application works with version 2 of the UIP Application Block. The main changes are in the calls to the StartTask method on the UIPManager class and in the constructor on the ControllerBase class.

To migrate an application from version 1 to version 2

  1. Replace calls to the StartTask method with one of the overloaded StartNavigationTask, StartOpenNavigationTask, or StartUserControlsTask methods on the UIPManager class in UIP version 2. For more information, see "Starting and Resuming Tasks," later in this chapter.
  2. Replace the constructor for your class that inherits from the ControllerBase class with a constructor that accepts the navigator you are using as a parameter. For more information, see "Creating the Controller," later in this chapter.

Developing an Application with the UIP Application Block

The main elements you need to develop if you are using the UIP Application Block are:

  • The custom controller class — You create this by inheriting from the ControllerBase class supplied with the block. Use the base class to define the custom methods for the functionality and navigation within your application.
  • The views — You create the views for your specific application type, inheriting from the predefined view types in the block.
  • The configuration file — You define the classes to use for state management and process management, the controller class, the views in the process, and the navigation paths between them.
  • The State class — You may need to add information related to your business logic that you want to be stored in and retrieved from the State class.

At a high level, to create applications using the UIP Application Block, you need to do the following:

  • Separate the application into distinct user interface processes.
  • Select a navigator for each user interface process.
  • Determine the state persistence provider.
  • Build the UIP Application Block, and refer to it in your application.
  • Create the controller(s).
  • Construct your process flow by starting, resuming, linking, and nesting tasks.
  • Create the views.
  • Create the configuration file.
  • Add additional functionality.

The topics that follow detail these requirements.

Separating the Application into Distinct User Interface Processes

Before you can begin writing code for your application, you need to consider the requirements of your user interface processes. Applications are usually composed of many user interface processes. You should define user interface processes by looking at your business requirements, not your technological requirements. By separating these correctly, you can reuse your code more efficiently because the user interface processes are encapsulated into distinct functional units.

You should identify each user interface process in the application. Remember that you can link user interface processes by starting and resuming tasks programmatically. For example, in a travel booking application, you will have user interface processes to enter personal settings, purchase plane tickets, make hotel reservations, and make payments. Note that many of these are dependent on each other, but are still separate processes.

Selecting a Navigator for Each User Interface Process

Each user interface process has a control flow. You define the control flow for each user interface process through a navigator. There are four navigators you can choose from: the graph navigator, the wizard navigator, the user controls navigator, and the open navigator. Each navigator controls the transitions between views differently, and may or may not lock the user into a predefined series of views.

Graph Navigator

Use the graph navigator when you have well-defined and fixed transitions between views. You should know which transitions are possible from each view, because the user is locked into following a certain process. Outputs from each view lead to either another view or the termination of the task. The graph navigator can be used with either Windows-based applications or Web applications.

You should draw the user interface process as a flow between the views with the outputs of each view leading to other views. For an example of this, see the sample graph navigator in "Graph Navigator" in Chapter 2, "Design of the UIP Application Block." Use your diagram to help you configure the <startView>, <node>, and <navigateTo> elements of the <navigationGraph> section of the application configuration file.

Open Navigator

The open navigator provides you with the greatest degree of flexibility. Use it when you do not have well-defined transitions and when you have your own external navigation functionality. In the latter case, the external navigation figures out what view is next and uses the open navigator to display the view. Open navigation is most typically used in Web applications or with Windows Forms that do not have user controls.

User Controls Navigator

A user controls navigator allows the user flexibility in transitioning between views and is best used with complex forms that contain user controls. With this navigator, you can allow the user to freely switch between controls, or you can control the user's navigation to some degree. If you create controls that are reused on many Windows Forms or multiple times on a single Windows Form, then the user controls navigator is a good choice. The user controls navigator can only be used in Windows-based applications.

Wizard Navigator

The wizard navigator provides a way to transition between views in a wizard. The wizard navigator can only be used in Windows-based applications.

Note   For more information about the design of these navigators, see Chapter 2, "Design of the UIP Application Block."

Determining the State Persistence Provider

Each user interface process has a different task lifetime. For example, you may want a user to be able to resume a task that he or she started earlier in a different Web session or after closing a Windows application. Some tasks should be associated with a single user (for example, a checkout task in a retail site) or multiple users (for example, a support call being escalated through members of a helpdesk team). You can use the information in Table 3.1 to determine the best state persistence provider for your user interface process and application type.

Table 3.1: Attributes of State Persistence Providers

Persistence Provider Class NameTask is Assignable to Different UsersTask Can Span SessionsWindows-based Applications SupportWeb-based Applications SupportPersisted Data is Encrypted
SqlServerPersistState 
SecureSqlServerPersistState
SessionStatePersistence    
MemoryStatePersistence    
IsolatedStoragePersistence  
SecureIsolatedStoragePersistence 
Note   If you use the SecureSqlServerPersistState or SecureIsolatedStoragePersistence implementations, you must ensure that the encryption key exists in the expected path in the registry. For more information, see "Creating the <objectTypes> Section" in "Creating the Configuration File Section" later in this chapter.

There are many ways to approach state management, and each has its own advantages and disadvantages. The implementations included in the UIP Application Block are scalable, but may have performance implications. You should look at the features of each persistence provider, and determine which is most appropriate. Bear in mind that if you use the SecureSqlServerPersistState class or the SecureIsolatedStoragePersistence class, the performance of your application may be degraded. This is due to the cost of decrypting and encrypting your data on each read and write operation. For more information about each of the persistence providers, see "State Persistence Providers" in Chapter 2, "Design of the UIP Application Block."

Note   If the supplied providers do not meet your requirements, you can implement your own provider. For more details about how to do so, see "Customizing State Persistence," in Appendix A, "Extending the UIP Application Block."

Building and Referencing the UIP Application Block

Before you can use the UIP Application Block, you must build the block and then reference it in your application.

To build the UIP Application Block

  1. Open the UIProcess_cs.sln solution (found in the <installation location> folder).
  2. Build the solution. Doing so generates two assemblies:
    • Microsoft.ApplicationBlocks.Data.dll
    • Microsoft.ApplicationBlocks.UIProcess.dll

To reference the UIP Application Block in your application

  1. Set a reference to the UIP Application Block assembly Microsoft.ApplicationBlocks.UIProcess.dll.
  2. Set a reference to the Data Access Application Block assembly Microsoft.ApplicationBlocks.Data.dll.
  3. Add an Imports (Visual Basic) or using (C#) statement at the top of each source file that uses classes from the block to reference the Microsoft.ApplicationBlocks.UIProcess namespace. All UIP Application Block types are located within this namespace.

    The following code examples show how to reference the block in your source files.

    [Visual Basic]
    Imports Microsoft.ApplicationBlocks.UIProcess
    
    [C#]
    using Microsoft.ApplicationBlocks.UIProcess;
    

Creating the Controller

You need to create controller classes with logic to interact with the business layers of your application. Controller classes expose methods that the views can use to get data or invoke specific functions. You should create methods that the views will invoke to get the data they need to render, and methods to pass data to the controller class. The views can access state held by the controller, and can modify the data, but only the controller can perform operations with the data, such as sending it to a Web service.

You can create your controller by inheriting from the ControllerBase class provided in the UIP Application Block.

Note   For more information about the design of the ControllerBase class, see Chapter 2, "Design of the UIP Application Block."

To create a controller for use with your application, you need to:

  • Reference and inherit from the ControllerBase class.
  • Create the constructor for your class.
  • Add custom code.

Inheriting the ControllerBase Class

The following code shows how to reference and inherit from the ControllerBase class.

[Visual Basic]
Imports Microsoft.ApplicationBlocks.UIProcess

Public Class MyController
  Inherits ControllerBase
End Class

[C#]
using Microsoft.ApplicationBlocks.UIProcess;

public class MyController : ControllerBase
{
}

Creating the Constructor

The constructor for your class must accept the navigator you are using as a parameter. You must also call the constructor of the base class. The following code examples show how to do this.

[Visual Basic]
Public Sub New(ByVal navigator As Navigator)
  MyBase.New(navigator)
  . . .
End Sub

[C#]
public MyController(Navigator navigator) : base(navigator){}

Adding Custom Code

You must add code in your controller class to allow the user to navigate through your workflow process. You need to write one method for each action a user needs to undertake. Each method should execute relevant business logic and call the Navigate method with the NavigateValue passed as a parameter. The NavigateValue corresponds to the next view or node you specify. The following code examples show how to do this.

[Visual Basic]
Me.Navigate("AddedData")

[C#]
Navigate("AddedData");

Whenever you call this method, you must pass a valid NavigateValue; otherwise, UIP will throw an exception because the view is unknown. For backward compatibility with the first version of UIP, you can set the NavigateValue property on the State object, and then call the Navigate method, as follows.

[Visual Basic]
Public Sub AddDataToDatabase(ByVal SomeData As Object)
  ' call custom data access code to insert data into database
  Me.State.NavigateValue = "AddedData"
  Me.Navigate
End Sub

[C#]
public void AddDataToDatabase(object SomeData)
{
  // call custom data access code to insert data into database
  this.State.NavigateValue = "AddedData";
  this.Navigate();
}

You can also add code to your controller to link tasks or navigators together. For more information, see "Linking Tasks," later in this chapter.

Starting and Resuming Tasks

Before you can guide your users through the workflow you have defined for them, you must use the UIPManager class to start a task. The StartNavigationTask, StartOpenNavigationTask, or StartUserControlsTask methods have several public overloaded methods you can use to start a task. Table 3.2 explains the parameters that you can pass to the StartNavigationTask, StartOpenNavigationTask, or StartUserControlsTask methods.

Table 3.2: StartNavigationTask, StartOpenNavigationTask, or StartUserControlsTask Parameters

ParameterDescription
NavigatorThe name of the navigator defined in the application configuration file. It may refer to the name of the graph navigator, wizard navigator, open navigator, or user controls navigator.
TaskAn existing task whose state should be retrieved and used.
taskedThe ID of a previously saved task.
firstViewNameName of the first view using the open navigator.
taskArgumentsAny information that is required when starting or resuming an existing task.
Note   The task and taskId parameters are required only when you start a previously suspended task. These parameters are relevant only if you have implemented the ITask interface to provide the ability to suspend and restart tasks. For more information about implementing the ITask interface, see "Implementing the ITask Interface," in Appendix A, "Extending the UIP Application Block."

The navigator you are using, and whether or not you are starting a new task or starting a task that was previously suspended, determines which overloaded method you should use and which parameters you should pass to the method. Each of the methods is described in the sections that follow, organized by navigator type.

Starting and Resuming Tasks with the Graph Navigator

If you are using the graph navigator and starting a new task, you must pass the name of the graph navigator as a parameter, as shown in the following code examples.

[Visual Basic]
UIPManager.StartNavigationTask("MyNavGraph")

[C#]
UIPManager.StartNavigationTask("MyNavGraph");

If you are using the graph navigator and starting a task that was previously suspended, you need to pass the name of the graph navigator and either the task or the task ID. The following code examples show the methods you can use to resume a task with a graph navigator.

[Visual Basic]
UIPManager.StartNavigationTask("MyNavGraph", MyTask)
UIPManager.StartNavigationTask("MyNavGraph", MyTaskID)

[C#]
UIPManager.StartNavigationTask("MyNavGraph", MyTask);
UIPManager.StartNavigationTask("MyNavGraph", MyTaskID);

Starting and Resuming Tasks with the Open Navigator

If you are using the open navigator and starting a new task, you need to pass the name of the open navigator and the name of the first view as a parameter, as shown in the following code examples.

[Visual Basic]
UIPManager.StartOpenNavigationTask("MyOpenNav", "MyFirstViewName")

[C#]
UIPManager.StartOpenNavigationTask("MyOpenNav", 
"MyFirstViewName");

If you are using the open navigator and starting a task that was previously suspended, you must pass the name of the open navigator and either the task object or the task ID. You may also specify the name of the first view when passing a task object. This name is used if the current view is not already stored in the State object. The following code examples show the methods you can use to resume a task with an open navigator.

[Visual Basic]
UIPManager.StartOpenNavigationTask("MyOpenNav", MyTask)
UIPManager.StartOpenNavigationTask("MyOpenNav", MyTaskID)
UIPManager.StartOpenNavigationTask("MyOpenNav", "MyFirstViewName", 
MyTask)

[C#]
UIPManager.StartOpenNavigationTask("MyOpenNav", MyTask);
UIPManager.StartOpenNavigationTask("MyOpenNav", MyTaskID);
UIPManager.StartOpenNavigationTask("MyOpenNav","MyFirstViewName", 
MyTask);

Starting and Resuming Tasks with the User Controls Navigator

If you are using the user controls navigator and starting a new task, you must pass the name of the user controls navigator as a parameter, as shown in the following code examples.

[Visual Basic]
UIPManager.StartUserControlsTask("MyUserControlsNav")

[C#]
UIPManager.StartUserControlsTask("MyUserControlsNav");

If you are using the user controls navigator and starting a task that was previously suspended, you must pass the name of the user controls navigator and either the task object or the task ID. You can pass data to the tasks by using the overloaded method containing the TaskArgumentsHolder parameter. You can use the methods shown in the following code examples to resume a task with a user controls navigator.

[Visual Basic]
UIPManager.StartUserControlsTask("MyUserControlsNav", MyTask)
UIPManager.StartUserControlsTask("MyUserControlsNav", MyTaskID)
UIPManager.StartUserControlsTask("MyUserControlsNav", MyTask, 
MyTaskArgs)
UIPManager.StartUserControlsTask("MyUserControlsNav", MyTaskID, 
MyTaskArgs)

[C#]
UIPManager.StartUserControlsTask("MyUserControlsNav", MyTask);
UIPManager.StartUserControlsTask("MyUserControlsNav", MyTaskID);
UIPManager.StartUserControlsTask("MyUserControlsNav", MyTask, 
MyTaskArgs);
UIPManager.StartUserControlsTask("MyUserControlsNav", MyTaskID, 
MyTaskArgs);
Note   If you pass a task object that is null, you are actually starting (and not resuming) a task. You may also use any of the overloaded methods to start a task by passing a null task object.

Linking Tasks

As a user navigates through an application, he or she often needs to use more than one user interface process to complete the job. Sometimes the user interface processes follow a linear path, and at other times one user interface process branches to another process and then returns to the original. For example, when shopping online, a user typically works through a Shopping user interface process and then moves to a Checkout user interface process. However, during the Checkout user interface process, the user may want to enter an alternative shipping address, meaning that the user must complete an Add Ship Address user interface process, and then return to and complete the Checkout user interface process. These tasks — including the optional additional tasks — are linked.

There are four concepts involved in linking tasks:

  • Starting tasks — You can start a task by calling any of the navigation start task methods or by calling the OnStartTask on your controller.
  • Ending tasks — You can end a task by calling either the SuspendTask or the OnCompleteTask method on your controller. Both methods allow the user interface process to clear the state for the current task and erase the current view from memory. However, the SuspendTask method does not remove the task from the state persistence provider. To clear the State object from both memory and from the state persistence provider, you must call the OnCompleteTask method.
  • Resuming tasks — You can resume a task that has been suspended by calling a navigation start task method (passing the task identifier or the task object that you want to resume), or by calling the OnStartTask method of an existing controller (passing the task identifier, the task object, or task arguments).
  • Passing data between tasks — You can pass data between tasks by using the OnStartTask overload with the TaskArgumentsHolder parameter. You can use this parameter to pass any data you want, and if the controller of the current view implements the EnterTask method, it can handle that data appropriately.

    The TaskArgumentsHolder parameter contains a property of type object, meaning that you can pass any type of data by using this property. You should not pass an instance of the controller itself, nor should you pass the controller's State object. This is because each task should have its own State object of the type specified in the graph navigator. Instead, you should pass your own types or common data classes. If you design your own structs or types, remember that you need to reference them from both the caller and the callee.

    Note   You can link tasks that have different types of navigators. The name of the navigator that is passed to the OnStartTask method determines what type of navigator is appropriate for your task.

The UIP Application Block allows you to link tasks in two ways: by chaining, or by nesting.

Chaining Tasks

You should chain tasks when you want one task to begin when another one ends, as shown in Figure 3.1.

ms979215.uipc0301(en-us,MSDN.10).gif

Figure 3.1: Chaining tasks

When you chain two tasks, you can pass data between them before ending the first task. For example, a user may be booking a flight and hotel accommodations using a Purchase Plane Ticket process followed by a Book Hotel process. If both of these bookings require the same Booking ID, then you must pass that ID between the tasks.

The following steps use this example to describe how to chain tasks in your controller:

  1. In the method of your controller class for the Purchase Plane Ticket process, store the Booking ID from the task state into a local variable.
  2. Invoke the SuspendTask method to suspend the Purchase Plane Ticket task.
  3. Invoke the OnStartTask method, passing the name of the next navigator and the event Booking ID as part of the TaskArgumentsHolder.
  4. In the controller for the first view of the Book Hotel process, implement the EnterTask method, retrieve the Booking ID from the TaskArgumentsHolder, and place it in the current task's State object. The first view of the Book Hotel process is displayed and the task continues.

For a complete example of how to chain tasks, see the MultiNavGraph QuickStart included with the UIP Application Block.

Nesting Tasks

Nesting tasks simply extends the concepts of chaining, but requires you to pass data back and forth, and to re-enter a running task. One task flows control into another, which is executed and ended, and control returns to the original task. This process is illustrated in Figure 3.2.

ms979215.uipc0302(en-us,MSDN.10).gif

Figure 3.2: Nesting tasks

For example, you may need to allow a user to run an Add New Shipping Address process while he or she is partially through the Purchase Product process. Once the new address is saved, the Add New Shipping Address process needs to end and the Purchase Product process needs to continue, using the new address.

The following steps use this example to describe how to nest tasks in your controller:

  1. In the method of your controller class for the Purchase Product process, store the CustomerId and TaskId from the task state into a local structure or collection. You must pass the TaskId, so the nested process knows the task to which it must return control.
  2. Invoke the OnStartTask method, passing the name of the next navigator, the customer information as part of the TaskArgumentsHolder, and the TaskId.
  3. In the controller for the first view of the Add New Shipping Address process, implement the EnterTask method, retrieve the CustomerId and TaskId from the TaskArgumentsHolder, and place them in the current task's State object. The first view of the Add New Shipping Address process is displayed and the task continues.
  4. When the Add New Shipping Address process is ready to return, retrieve the TaskId for the Purchase Product process, which is stored in the current task's state, and invoke the OnStartTask method, passing the name of the navigator, the new address, and the original TaskId. If the task state for the specified task is found, the current view for that task is displayed.

Creating Views

You need to create or reuse the user interface components for the views in your application. For each node in the process, you should design a view that displays data to, or gets data from, the user. The views should invoke methods on the controllers to set data, but can retrieve the state of the controller directly.

You can create views in your application by performing the following steps:

  1. Inherit from the appropriate view class. There are three view classes in the UIP Application Block: WebFormView, WindowsFormView, and WindowsFormControlView.
  2. Implement the Initialize method to access custom view information, such as background color. For more information see "Adding Extensible Configuration Schema" later in this chapter.
  3. Write code to access the controller for each view in the user interface process.
  4. Add navigation code to your views by calling the methods defined in your controller class.

The AdvancedHostDemo QuickStart demonstrates how to use the WindowsFormControlView class to create user control views. You can also define your own custom views by implementing the IView interface. For more information, see "Customizing Views and View Management" in Appendix A, "Extending the UIP Application Block."

Inheriting from the Base Class

All views that are to be controlled by the UIP Application Block must inherit from the relevant view base class or must implement the IView interface. If you create your own implementation of IView, you must create the associated view manager as well. The first view in the application does not need to inherit from the view base class; it is not until after this view is created that the controlling objects are created.

Inheriting the WebFormView Class

The following example code shows how to inherit from the WebFormView class:

[Visual Basic]
Public Class WebForm2
  Inherits WebFormView
End Class

[C#]
public class WebForm2 : WebFormView

The WebFormView class is inherited from the System.Web.UI.Page class; therefore, you do not need to explicitly inherit from that class.

Inheriting the WindowsFormView Class

The following example code shows how to inherit from the WindowsFormView class.

[Visual Basic]
Public Class Form2
  Inherits WindowsFormView
End Class

[C#]
public class WinForm2 : WindowsFormView

The WindowsFormView is inherited from the System.Windows.Forms.Form class; therefore, you do not need to explicitly inherit from that class.

Inheriting the WindowsFormControlView Class

The following example code shows how to inherit from the WindowsFormControlView class.

[Visual Basic]
Public Class Form2
  Inherits WindowsFormControlView
End Class

[C#]
public class WinForm2 : WindowsFormControlView

The WindowsFormControlView is inherited from the System.Windows.User.UserControl class; therefore, you do not need to explicitly inherit from that class.

Accessing the Controller

To use the controller navigation methods, you need to write code to access the controller for each view in the process. The following example code shows how this can be done.

[Visual Basic]
Private ReadOnly Property MyController() As MyController
  Get
    Return CType(Me.Controller, MyController)
  End Get
End Property

[C#]
private MyController MyController
{
  get{ return (MyController)this.Controller; }
}

Adding the Navigation Code

To add the navigation abilities to your views, you call the methods defined in your controller class. The following example code shows how to call the controller method shown earlier.

[Visual Basic]
MyController.AddDataToDatabase(SomeData)

[C#]
MyController.AddDataToDatabase(SomeData);

You should make any property changes to your State object within the controller methods, not directly from your views. This ensures that the controller can intercept these calls, and makes some of the custom state management techniques simpler to implement.

Note   If you receive exceptions stating that a view cannot be created, you may have errors in your configuration file, errors in the constructor of the view, or errors initializing the controller of the view.

Creating the Configuration File

The XML-based configuration file is used to define the classes that play the major roles in your application user interface process, the views that are used, and the navigators that define the workflow paths for the application.

The contents of the configuration file are similar for all application types. Generally, in Web applications, you work with Web.config, and in Windows-based applications, you work with the app.config file.

Defining the uipConfiguration Section

You must add a new configuration section to the configuration file to define your UIP configuration settings. This section must be declared in the <configSections> section of the file as shown in the following code.

<configuration>
  <configSections>
    <section name="uipConfiguration"
      type="Microsoft.ApplicationBlocks.UIProcess.UIPConfigHandler,
      Microsoft.ApplicationBlocks.UIProcess,
      Version=1.0.1.0,Culture=neutral,PublicKeyToken=null" />
  </configSections>
</configuration>

Creating the uipConfiguration Section

You need to create the <uipConfiguration> section itself. This section is used to define the classes to be used by the application for view management, state management, and controllers, the views available to the user, and the navigators that define the workflow path through those views.

The structure of this section is defined in the XML Schema Definition (XSD) file called UIPConfigSchema.xsd, which is included in the block. This schema details which elements and attributes are required and which are optional, how many times each may occur, and in what order they should occur. If the required elements of the <uipConfiguration> section do not adhere to the schema, exceptions are thrown when the UIPConfigHandler class attempts to parse and validate the configuration section.

There are minor differences in the contents of this section depending on the type of application that you are developing. Examples for Web applications and Windows-based applications are included in this section.

The structure of the <uipConfiguration> section is shown in the following code. The sections in italics are optional.

<uipConfiguration enableStateCache="true">
  <objectTypes>
    . . .
  </objectTypes>
  <views>
    . . .
  </views>
  <sharedTransitions>
    . . .
  </sharedTransitions>
  <navigationGraph>
    . . .
  </navigationGraph>
  <uipWizard>
    . . .
  </uipWizard>
  <userControls>
    . . .
  </userControls>
</uipConfiguration>
Note   If you want to allow users to navigate to views by specifying a URL or by clicking on the back or forward buttons in a Web browser in your Web applications, you must set the allowBackButton attribute to true. For example, the <uipConfiguration> section may begin with the following line:
<uipConfiguration enableStateCache="true" allowBackButton="true">
If you enable the allowBackButton attribute, state is not rolled back when your user clicks the back button. For example, if a user has items in a shopping cart and he or she clicks the back button, the user still has the same items in his or her shopping cart. For more details about how the UIP Application Block uses conditional logic to determine how the user navigates, see the "Navigator" section in Chapter 2, "Design of the UIP Application Block."

The sections are briefly described in Table 3.3.

Table 3.3: <uipConfiguration> Sections

Section NameDescription
objectTypeDefines the classes to be used for managing and controlling the user interface process in an application.
viewsDefines the details of the views to be used in an application.
sharedTransitions (optional)Defines the common transition points for all views.
navigationGraph (optional)Defines the details of the graph navigator. Required by each task that uses a graph navigator. Used to define wizards that support branching.
uipWizard (optional)Defines the details of the wizard navigator. Used to define simple wizards that do not support branching.
userControls (optional)Defines the details of the user controls navigator. Required by each task that uses a user controls navigator.

For each task that uses a wizard navigator, you must either define the wizard navigator in the <uipWizard> element or in the <navigationGraph> element. The wizard defined by the <uipWizard> element supports linear navigation, and the wizard defined by the <navigationGraph> element supports branching. If you define a wizard with the <navigationGraph> element, you must set the runInWizardMode attribute to true. Any of your wizard views that support branching must implement the IWizardViewTransition interface. For an example of this, see the InsurancePurchaseWizard QuickStart.

If you are using the open navigator, you do not need to define any of the optional sections because you call the views directly. However, all valid views need to be specified in the <views> section of the configuration file.

Note   If you are developing an application with both a Web and a Windows interface to the same underlying state, and you expect both interfaces to be used on the same computer, you should not cache the state. If you do cache the state, the cached version from the Web application may overwrite later changes that have been made using the Windows version. To disable caching of state, set the enableStateCache attribute of the <uipConfiguration> section to false.

The following sections describe how to define each of these configuration sections.

Creating the <objectTypes> Section

The <objectTypes> section defines the classes used for managing and controlling the user interface process in a Windows or Web application. The sections are shown in the following code; the <layoutManager> section is optional.

<objectTypes>
  <iViewManager . . . />
  <state . . . />
  <controller . . . />
  <layoutManager . . . />
  <statePersistenceProvider . . . />
</objectTypes>

The sections are briefly described in Table 3.4.

Table 3.4: <objectTypes> Sections

Section NameDescription
iViewManagerSpecifies the view manager responsible for activating and deactivating views within the application.
stateControls the state of your application. Can be extended to include application-specific state attributes.
controllerControls the flow of the views and responds to requests from views.
layoutManager (optional)Performs custom layout of controls on a view.
statePersistenceProviderSpecifies the location where the state should be saved between view transitions.

Each of these sections requires specific attribute settings to link it to the relevant class in the UIP Application Block. Table 3.5 defines the attributes required by each of the elements in the <objectTypes> section.

Table 3.5: Configuration Attributes of the <objectTypes> Elements

Attribute NameDescription
nameThe name used to refer to this object within the configuration file and block code.
typeThe type information for this object, which identifies the assembly where the object is defined and its class name.

If you use the SecureSqlServerPersistState or SecureIsolatedStoragePersistence implementations, you must ensure that the encryption key exists in the expected path in the registry. You can set this key in one of two ways:

  • Run the InstallDemos.vbs file to create the registry key. This file is included with this block.
  • Add the registryPath attribute to the <statePersistenceProvider> node of the <objectTypes> element in the configuration file, and set the value of the attribute to the registry path you want to use.

If you use the SqlServerPersistState or SecureSqlServerPersistState implementations, you also need to set a connectionString attribute that provides connection information for the SQL Server database.

The following code is an example of the <objectTypes> section.

<objectTypes>
  <iViewManager
    name="WebFormViewManager"
    
type="Microsoft.ApplicationBlocks.UIProcess.WebFormViewManager,
    Microsoft.ApplicationBlocks.UIProcess,
    Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

  <state
    name="State"
    type="Microsoft.ApplicationBlocks.UIProcess.State,
    Microsoft.ApplicationBlocks.UIProcess,
    Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

  <controller
    name="MyController"
    type="Test.MyController, Test,
    Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

  <layoutManager
    name="HorizontalLayoutManager"
    type="LayoutManager.HorizontalLayoutManager, LayoutManager,
    Version=1.0.1.0,Culture=neutral,PublicKeyToken=null" />

  <layoutManager
    name="VerticalLayoutManager"
    type="LayoutManager.VerticalLayoutManager, LayoutManager,
    Version=1.0.1.0,Culture=neutral,PublicKeyToken=null" />

  <statePersistenceProvider
    name="SqlServerPersistState"
    
type="Microsoft.ApplicationBlocks.UIProcess.SqlServerPersistState,
    Microsoft.ApplicationBlocks.UIProcess, Version=1.0.0.0,
    Culture=neutral, PublicKeyToken=null"
    connectionString="Data Source=localhost;Initial 
Catalog=UIPState;
    Trusted_Connection=True"/>
</objectTypes>
Note   Exceptions thrown from the GenericFactory class when creating objects may be due either to errors in your configuration file (such as invalid assembly/class names) or to errors in the constructor of the object you are trying to create.

Creating the <views> Section

The <views> section defines the details of the views to be used in the Web or Windows application. Each element requires three attributes: the name, type, and controller. In Windows-based applications, you can use the optional attributes as described in Table 3.6. The layoutManager and any attributes are optional in both Web and Windows-based applications.

Table 3.6: Configuration Attributes of the <view> Section

Attribute NameDescription
nameThe name of the view as referred to in the navigator.
typeThe class name of the class that defines this view.
controllerThe name of the controller as defined in the <objectTypes> section to be used for this view.
layoutManager (optional)The name of layout manager.
stayOpen (optional)Whether the view should remain open when the user navigates away from it.
openModal (optional)Whether the view should be opened as a modal view. If openModal is set to true, then stayOpen should be set to false.
canHaveFloatingWindows (optional)Whether the view can host floating windows.
floatable (optional)Whether the view should float.
any (optional)You can augment your view information with custom elements or attributes.

The following code is an example of the <views> section for a Web application. This example shows the definition of five views, all identifying ASP.NET Web pages.

<views>
  <view name="Page1" type="Page1.aspx" controller="MyController" 
/>
  <view name="Page2" type="Page2.aspx" controller="MyController" 
/>
  <view name="Page3" type="Page3.aspx" controller="MyController" 
/>
  <view name="Page4" type="Page4.aspx" controller="MyController" 
/>
  <view name="Error" type="Error.aspx" controller="MyController" 
/>
</views>

The following code is an example of the <views> section for a Windows application. This example shows the definition of five views, all linked to Windows Forms.

<views>
  <view
    name="Form1"
    type="Demo.Form1, Demo, Version=1.0.0.0, Culture=neutral,
    PublicKeyToken=null"
    controller="MyController"
    layoutManager="VerticalLayoutManager"
    stayOpen="true"/>
  <view
    name="Form2"
    type="Demo.Form2, Demo, Version=1.0.0.0, Culture=neutral,
    PublicKeyToken=null"
    controller="MyController" />
  <view
    name="Form3"
    type="Demo.Form3, Demo, Version=1.0.0.0, Culture=neutral,
    PublicKeyToken=null"
    controller="MyController" />
  <view
    name="Form4"
    type="Demo.Form4, Demo, Version=1.0.0.0, Culture=neutral,
    PublicKeyToken=null"
    controller="MyController" />
  <view
    name="Error"
    type="Demo.Error, Demo, Version=1.0.0.0, Culture=neutral,
    PublicKeyToken=null"
    controller="MyController"
    stayOpen=false
    openModal=true />
</views>

If the ShowModal method is called on the next view and the view's openModal attribute is set to true, then the current view becomes the parent form and the view manager disables the parent form, but leaves it open when the view is activated. Once the user has closed the view, the view manager enables the parent form.

If the view's floatable attribute is set to true, the view manager determines whether the parent form's canHaveFloatingWindows attribute is set to true. If so, the view manager leaves the parent view enabled but behind the floating window view.

You can add customized settings for each of your views to this section of the configuration file using the any attribute. For more information, see "Adding Extensible Configuration Schema," later in this chapter.

Creating the <sharedTransitions> Section

An application may have views that are a common transition point for nodes within a single graph navigator or for all graph navigators. This section is relevant only if you have the <navigationGraph> section defined. If the views have common transition points, they are global transition points. The following code is an example of a global transition point.

<sharedTransitions>
    <sharedTransition navigateValue="storehelp" 
navigateTo='storehelp' />
</sharedTransitions>

For information about how to add shared transitions a specific graph navigator, see "Adding Shared Transitions to the <navigationGraph> Section" later in this chapter.

Creating the <navigationGraph> Section

The <navigationGraph> section defines the details of the graph navigator. It also declares the objects to be used for navigation management. The <navigationGraph> section contains a number of attributes as described in Table 3.7.

Table 3.7: Configuration Attributes of the <navigationGraph> Section

Attribute NameDescription
startViewThe name of the first view to be shown within the process. Note that this is not necessarily the first view that the user sees, but the first view referenced in the graph navigator.
iViewManagerThe name of the view manager as defined in the <objectTypes> section.
nameThe name of the graph navigator.
stateThe name of the state type as defined in the <objectTypes> section.
statePersistThe name of the state persistence mechanism as defined in the <objectTypes> section.
cacheExpirationMode (optional)The expiration method used to invalidate items in the cache.
cacheExpirationInterval (optional)The expiration interval used before invalidating items in the cache. For absolute expiration, the cacheExpirationInterval should be specified as the absolute time of day when the item should expire. For sliding expiration, the cacheExpirationInterval should be specified as the time, in milliseconds, before the item should expire.
runInWizardMode (optional)Specifies that this is a wizard navigator for Windows-based applications. Used to support wizards with branching capabilities.

The <navigationGraph> section also contains a number of <node> elements, each of which define a node within the graph navigator. The view attribute of the node identifies the view as defined in the views section, and you can use the <navigateTo> elements to identify the navigational routes for this view. The <navigateTo> elements have two attributes as described in Table 3.8.

Table 3.8: Configuration Attributes of the <navigateTo> Elements

Attribute NameDescription
navigateValueThe value that is assigned to an action in the code to identify the route to be taken.
viewThe view that should be navigated to when this navigateValue is used.

The following code is an example of the <navigationGraph> section for a Web application.

<navigationGraph
  startView="Page2"
  iViewManager="WebFormViewManager"
  name="MyNavigationGraph"
  state="State"
  statePersist="SqlServerPersistState"
  cacheExpirationMode="Sliding"
  cacheExpirationInterval="1000">

  <node view="Page2">
    <navigateTo navigateValue="MoreInfo" view="Page3"/>
    <navigateTo navigateValue="DataAdded" view="Page4" />
    <navigateTo navigateValue="fail" view="error" />
  </node>
  <node view="Page3">
    <navigateTo navigateValue="DataAdded" view="Page4" />
    <navigateTo navigateValue="fail" view="error" />

  </node>
  <node view="Page4">
    <navigateTo navigateValue="Restart" view="Page1" />
    <navigateTo navigateValue="fail" view="error" />
  </node>
  <node view="Error">
    <navigateTo navigateValue="Page1" view="Page1" />
    <navigateTo navigateValue="Page2" view="Page2" />
    <navigateTo navigateValue="Page3" view="Page3" />
    <navigateTo navigateValue="Page4" view="Page4" />
  </node>
</navigationGraph>

The following code is an example of the <navigationGraph> section for a Windows application.

<navigationGraph
  startView="Form2"
  iViewManager="WindowsFormViewManager"
  name="MyNavigationGraph"
  state="State"
  statePersist="SqlServerPersistState" >

  <node view="Form2">
    <navigateTo navigateValue=" MoreInfo" view="Form3"/>
    <navigateTo navigateValue="DataAdded" view="Form4" />
    <navigateTo navigateValue="fail" view="error" />
  </node>
  <node view="Form3">
    <navigateTo navigateValue="DataAdded" view="Form4" />
    <navigateTo navigateValue="fail" view="error" />
  </node>
  <node view="Form4">
    <navigateTo navigateValue="Restart" view="Form1" />
    <navigateTo navigateValue="fail" view="error" />
  </node>
  <node view="Error">
    <navigateTo navigateValue="Form1" view="Form1" />
    <navigateTo navigateValue="Form2" view="Form2" />
    <navigateTo navigateValue="Form3" view="Form3" />
    <navigateTo navigateValue="Form4" view="Form4" />
  </node>
</navigationGraph>

The preceding examples show the previously declared views with their navigational routes now defined. Notice that each view has a <navigateTo> element with a fail value pointing to the error view. It is good practice to include a global error page that can be reached from each page, and then if the controller detects an irresolvable error, it can safely navigate to your error page.

Adding Shared Transitions to the <navigationGraph> Section

An application may have views that are a common transition point for nodes within a single graph navigator. To add shared transitions to the <navigationGraph> section, you should modify the configuration file, as shown in the following example.

<navigationGraph
    iViewManager="WindowsFormViewManager"
    name="Shopping"
    state="State"
    statePersist="SqlServerPersistState"
    startView="cart"
    >
<sharedTransitions>
    <sharedTransition navigateValue="shoppinghelp" 
navigateTo='shoppinghelp'/>
</sharedTransitions>

In the preceding example, a navigateValue of shoppingHelp issued from any of the forms would result in navigation to the shoppinghelp view. Note that a specific form can also have a specification of a view for shoppingHelp; that specification takes precedence over the shared transition specification.

Creating a <uipWizard> Section

The <uipWizard> section is a quick way to create a graph navigator that supports linear navigation. The next, previous, finish, and cancel transitions are provided for all nodes. The name of the wizard navigator and each view that appears in the wizard should be provided in the correct sequence. The following code is an example of a <uipWizard> section of a configuration file.

<uipWizard name="CarWizard">
    <sequence view="ClientInfo"/>
    <sequence view="CarInfo"/>
    <sequence view="Confirmation"/>
</uipWizard>

The InsurancePurchaseWizard QuickStart demonstrates the wizard functionality for UIP in a Windows Forms application.

Creating the <userControls> Section for a Windows Application

The <userControls> section defines the navigational details of a user control navigator for a Windows application. The <userControls> section contains a number of attributes as described in Table 3.9.

Table 3.9: Configuration Attributes of the <userControls> Section

Attribute NameDescription
startFormThe name of the first form to be shown within the process. Note that this is not necessarily the first view that the user will see, but the first view referenced in the user controls navigator.
iViewManagerThe name of the view manager as defined in the <objectTypes> section.
nameThe name of the navigator.
stateThe name of the state type as defined in the <objectTypes> section.
statePersistThe name of the state persistence mechanism as defined in the <objectTypes> section.
cacheExpirationMode (optional)The expiration method to use to invalidate items in the cache.
cacheExpirationInterval (optional)The expiration interval to use before invalidating items in the cache. For absolute expiration, the cacheExpirationInterval should be specified as the absolute time of day when the item should expire. For sliding expiration, the cacheExpirationInterval should be specified as the time, in milliseconds, before the item should expire.

The <userControls> section also contains a number of <form> elements, each of which defines a form within the task as shown in Table 3.10. Each <form> element has a name attribute, which defines the view instance.

The <form> element may contain a number of <childView> elements, each of which defines a control on the form that derives from the WindowsFormControlView class.

Table 3.10: Configuration Attributes of the <UserControls> <childView> Elements

Attribute NameDescription
nameThe name of the instance of the view on the form; for example, a billing or shipping address.
viewNameThe name of the view type from the views section of the configuration file.

The following is an example of the <userControls> section of a configuration file.

<userControls name="Shop"
    startForm="StoreForm"
    iViewManager="WindowsFormViewManager"
    state="State"
    statePersist="SqlServerPersistState">
    <form name="StoreForm">
        <childView name="shoppingCart" viewName="cart"/>
        <childView name="catalog" viewName="browsecatalog"/>
    </form>
</userControls>

Adding Additional Functionality

If you have implemented the requirements specified earlier in this chapter, your applications will support the UIP Application Block. However, the block has some additional features that you can make use of, as this section describes.

Adding Extensible Configuration Schema

The UIP Application Block gives you the ability to have view-specific attributes, such as background color, stored with the view configuration information. The block validates configuration information against a supplied XML schema. Because these attributes are application-specific, the UIP schema has no knowledge of them and therefore cannot validate them. Your code is responsible for validating the schema and semantics of these extra attributes.

To add extensible configuration schema, add any custom attributes to the <views> section of the configuration file, as shown in the following code example.

<view name="customView" 
type="UIProcessQuickstarts_Store.WinUI.CustomView,
UIProcessQuickstarts_Store.WinUI,Version=1.0.1.0,Culture=neutral,
PublicKeyToken=null"
controller="StoreController" bgColor="Yellow">

<Captions>
<caption control="button1" text="Hello" />
<caption control="button2" text="Goodbye" />
</Captions>
</view>

Attributes are supported per view, and are interpreted by the view manager. The UIP Application Block passes unrecognized attributes or elements to the view manager and to the view (in the view's Initialize method) during execution. You must implement the Initialize method to access custom view information. The following example code shows how to access this information programmatically from the Initialize method. In this example, you must reference the System.Xml.XPath namespace because it uses an XPathNodeIterator type.

[Visual Basic]
Public Sub Initialize(ByVal args() As Object,ByVal settings As 
ViewSettings)
MyBase.Initialize(args, settings)

'retrieving a custom attribute
Me.BackColor = 
Color.FromName(settings.CustomAttributes.Item(0).Value)

'retrieving information from custom elements
Dim iterator as XPathNodeIterator = 
settings.Navigator.Select("descendant::Captions/caption")

While (iterator.Movenext())
    'reference the caption node
    Dim navigator As XPathNavigator = iterator.Current
    'reference controls and set properties using attributes on the 
current caption node
Dim control as Control = 
FindControlByName(navigator.GetAttribute("control",navigator.Names
paceUR))

Control.Text = 
navigator.GetAttribute("text",navigator.NamespaceURI)
End While
End Sub

[C#]
public override void Initialize(object[] args, ViewSettings 
settings)
{
base.Initialize (args, settings);

//retrieving a custom attribute
this.BackColor = 
Color.FromName(settings.CustomAttributes.Item(0).Value);

//retrieving information from custom elements
XPathNodeIterator iterator = 
settings.Navigator.Select("descendant::Captions/caption");
   while (iterator.MoveNext())
   {
   // reference the caption node
   XPathNavigator navigator = iterator.Current;
   // reference controls and set properties using attributes on 
the
   // current caption node
   Control control =
   
FindControlByName(navigator.GetAttribute("control",navigator.
NamespaceURI));
   control.Text = 
navigator.GetAttribute("text",navigator.NamespaceURI);
   }
}

Raising Navigation Events

The UIP Application Block allows your application to listen for a navigate event. Navigate events are raised after the Navigate method is called on the controller, but before the actual navigation takes place. This gives you one last opportunity to modify the NavigateValue property on the State class — or to perform any other function — before the user is taken to the next view.

You need to define the NavigateEvent event in the UIPManager class as shown in the following code example.

[Visual Basic]
AddHandler UIPManager.NavigateEvent,AddressOf 
UIPManager_NavigateEvent

[C#]
UIPManager.NavigateEvent +=
New Microsoft.ApplicationBlocks.
UIProcess.UIPManager.NavigateEventHandler
(UIPManager_NavigateEvent);

You also need to define the corresponding event handler, which might look something like this.

[Visual Basic]
Private Sub UIPManager_NavigateEvent(ByVal sender As Object,
ByVal e As EventNavigateArgs)
    'Some logic that is performed on the navigate event
    'You can obtain the state from the NavigateEventArgs: e.State
    'You can change the navigate value like this:
    ' e.State.NavigateValue = someNewNavigateValue
End Sub

[C#]
private void UIPManager_NavigateEvent(object sender, 
EventNavigateArgs e)
{
// Some logic that is performed on the navigate event
// You can obtain the state from the NavigateEventArgs: e.State
// You can change the navigate value like this:
// e.State.NavigateValue = someNewNavigateValue;
}

Raising navigation events is demonstrated in the InsuranceClientManagement QuickStart.

Responding to Changes in State

The UIP Application Block allows your application to listen for a StateChanged event. Your views can subscribe to this event so that they are notified when the state changes, and, if necessary, can update themselves. If you derive from the State class, you must ensure you raise this event whenever you change an item of state. For details, see "Creating a Strongly Typed Class" in Appendix A, "Extending the UIP Application Block."

The following example handles the StateChanged event and uses it to display a message box.

[Visual Basic]
Private Sub Page2_Load(ByVal sender As Object, ByVal e As 
System.EventArgs)
  myState = MyController.State
  myState.StateChanged += New 
State.StateChangedEventHandler(myState_StateChanged)
End Sub

Private Shared Sub myState_StateChanged(ByVal sender As Object, _
                                        ByVal e As 
StateChangedEventArgs)
  Dim result As DialogResult
  result = MessageBox.Show( _
           "State has changed. Would you like to update 
your view?", _
           "State Changed", MessageBoxButtons.YesNo)
  If result = DialogResult.Yes Then
    ' Update view
  End If
End Sub

[C#]
private void Page2_Load(object sender, System.EventArgs e)
{
  myState = MyController.State;
  myState.StateChanged+=new 
State.StateChangedEventHandler(myState_StateChanged);
}

private static void myState_StateChanged(object sender, 
StateChangedEventArgs e)
{
  DialogResult result;
  result = MessageBox.Show(
           "State has changed. Would you like to update your 
view?",
           "State Changed", MessageBoxButtons.YesNo);
  if(result == DialogResult.Yes)
  {
    // Update view
  }
}

Raising state events is demonstrated in the AdvancedHostDemo QuickStart.

UIP Shutdown

Classes that should be notified when a user interface process is complete need to implement the IShutdownUIP interface. The classes that implement the shutdown interface must be registered with the UIPManager class. The IShutdownUIP interface has one public method called Shutdown. For more information about when you would implement this interface, see "IShutdownUIP Interface" in Chapter 2, "Design of the UIP Application Block."

When the last UIP form closes, UIP detects that the windows have been closed and the registered classes' Shutdown method is invoked. Normally this method is used by the bootstrap form (the form that initiates the user interface process). When the user interface process is started, the bootstrap form visibility is usually set to hidden. When the user interface process is complete, the bootstrap form can be set to visible.

The following example shows how to register a shutdown task and implement the IShutdownUIP interface. See the AdvancedHostDemo QuickStart for more information.

[Visual Basic]
public Class StartMeUp : System.Windows.Forms.Form, IShutdownUIP
      Private Sub button1_Click(ByVal sender as Object, ByVal e as 
System.EventArgs)
            UIPManager.RegisterShutdown(Me)
            Me.Visible = false
            _startingTask = new TestTask
            UIPManager.StartUserControlsTask("demo", 
_startingTask)
      End Sub

      Public Sub Shutdown() Implements IShutdownUIP.Shutdown
            Me.Visible = true
      End Sub
End Class

[C#]
public class StartMeUp : System.Windows.Forms.Form, IShutdownUIP
{
      .....
      private void button1_Click(object sender,
 System.EventArgs e)
      {
            // register this class for shutdown
            UIPManager.RegisterShutdown(this);
            // hide this form
            this.Visible = false;
            _startingTask = new TestTask();
            // start UI process
            
UIPManager.StartUserControlsTask("demo",_startingTask);
      }

      #region IShutdownUIP Members
      // method invoked when UI process is completed
      public void Shutdown()
      {
            // makes form visible again
            this.Visible = true;
      }
      #endregion
}

Customizing View Layouts

To lay out controls on your views in a customized manner, you need to create a class that implements the ILayoutManager interface and defines the LayoutControls method. The ILayoutManager interface has one public method called LayoutControls. For more information about the ILayoutManager, see "ILayoutManager Interface" in Chapter 2, "Design of the UIP Application Block."

You also need to specify each of your custom layout managers in the <objectTypes> section of the configuration file, and specify the layout manager attribute for each view that uses the custom layout manager in the <views> section of the configuration file.

When the view is activated, if you have defined a layout manager and have specified the view to use the layout manager in the configuration file, the view manager calls the LayoutControls method on your layout manager and places the controls in the correct order. This method positions each control on the parent control that is passed as a parameter to this method (which is the form being activated).

QuickStarts for the UIP Application Block

To help you gain a better understanding of the UIP Application Block, several QuickStarts are included with the block:

  • AdvancedHostDemo QuickStart — Demonstrates the use of user controls and transitioning between user controls in a Windows Forms application.
  • InsuranceClientManagement QuickStart — Demonstrates some of the new functionality that has been added to UIP. Specifically, it demonstrates the shared transitions functionality and handling navigation events in a Windows Forms application.
  • InsurancePurchaseWizard QuickStart — Demonstrates the wizard functionality for UIP in a Windows Forms application.
  • NoNavGraph QuickStart — Demonstrates how you can use the open navigator in a Windows Forms application. This style of navigation allows you to make transitions without having to specify a navigator in the configuration file.
  • MultiNavGraph QuickStart — Demonstrates how to chain and nest tasks with multiple graph navigators in a Windows Forms application.
  • Store QuickStart — Demonstrates multiple aspects of the UIP Application Block for Windows-based applications and Web applications including user controls, random navigation, and shared transitions.
Important   The QuickStarts are intended to aid you in understanding the block; they are not intended to be production-ready code samples, and may not be indicative of the way you should develop your application.

To build the QuickStarts provided with the block, you need to ensure that your system meets the following minimum software requirements in addition to the minimum requirements for working with the UIP Application Block.

  • SQL Server 2000 or Microsoft SQL Desktop Engine (MSDE)
  • Internet Information Services (IIS) 5.0 or later

Building the QuickStarts is a relatively straightforward process. It consists of the following steps.

To build the UIP Application Block QuickStarts

  1. Locate the solution file for the QuickStart you want to build (located in the <installation location>\ApplicationBlocks\...\QuickStarts\cs\<QuickStartName> folder).
    Note   This discussion refers to files with a .cs file name extension. If you are using the Visual Basic versions of the samples, you should use the .vb file name extension instead.
  2. Build the solution.

The following sections discuss each QuickStart in more detail.

AdvancedHostDemo QuickStart

This QuickStart demonstrates the use of user controls and transitioning between user controls in a Windows Forms application. The user interface contains two user controls: the tree view on the left and the tab view on the right. When the user selects an item on the tree view, the information on the tab changes to reflect the information that corresponds to the selected item. When the user clicks the edit button, the user can edit the information in the tab view for that tree selection. This QuickStart also demonstrates handling the StateChanged event and demonstrates the extensible configuration schema functionality by adding custom attributes to the <views> section of the configuration file.

InsuranceClientManagement QuickStart

This QuickStart demonstrates some of the new functionality that has been added to UIP. Specifically, it demonstrates the shared transitions functionality and handling navigation events in a Windows Forms application. This Windows Forms application consists of a logon page that any user can view and a page that only authenticated users can view. The QuickStart illustrates how you can intercept navigation events to redirect unauthenticated users to the logon page.

InsurancePurchaseWizard QuickStart

This QuickStart demonstrates the wizard functionality for UIP in a Windows Forms application. The application consists of three wizards: InsurancePurchase Wizard, Car Wizard, and Home Wizard. The car wizard and home wizard behave in a straightforward manner with Next, Back, Cancel, and Finish transitions, and the sequence of views as defined in the application configuration file in the <uipWizard> section. The insurance purchase wizard gives the user more options than the straightforward wizard. Valid transitions are defined using a graph navigator, and the runInWizardMode attribute is set to true. This QuickStart also demonstrates how you can customize the behavior of views in the wizard by implementing the IWizardViewTransition interface.

NoNavGraph QuickStart

This QuickStart demonstrates how you can use the open navigator in a Windows Forms application. This style of navigation allows you to make transitions without having to specify a navigator in the application configuration file and allows you to navigate using view names. However, you must still specify the default values, including valid views, in the configuration file.

MultiNavGraph QuickStart

This QuickStart demonstrates how to link tasks that are defined in two separate graph navigators. It primarily shows how information and state can be passed between the two graph navigators. This application also contains a custom implementation of the ITask interface that records task entries into an XML file. Some of the features of the UIP Application Block that this application demonstrates are the stayOpen and openModal attributes. When a view has the openModal attribute set to true, the screen opens in a modal fashion and must be closed before the user can continue in other views that were open before it. When a view has the stayOpen attribute set to true, the screen stays open and visible even after transitions are made from it.

Store QuickStart

This QuickStart demonstrates multiple aspects of the UIP Application Block for Windows-based applications and Web applications, including the graph navigator, the user controls navigator, shared transitions, and preventing random navigation.

The random navigation functionality is only relevant in the Web application. This application demonstrates how to prevent random navigation by setting the allowBackButton attribute to false in the application configuration file. When this functionality is disabled, it prevents the user from transitioning back to the previous view by using the back button. It also prevents users from navigating to views by typing the URL for a particular view.

Conclusion

The UIP Application Block provides you with a flexible infrastructure that you can use to control the user interface process within a Windows or Web application. UIP provides you with a framework for creating views, controlling navigation, and persisting state. This chapter discussed the steps you would perform to use the UIP Application Block with your application. The QuickStarts supplied with the User Interface Process Block give you a useful starting point in understanding how to use the block.

Start | Previous | Next

Patterns and Practices home

Page view tracker