Intersoft ClientUI 8 > ClientUI Fundamentals > Navigation Overview > Advanced Features in ClientUI Navigation Framework |
This topic describes the advanced features in the ClientUI navigation framework to address a more complex requirements in line-of-business applications. For information about the basics of the navigation concept, see Navigation Overview.
This topic contains the following sections:
By default, when you add a new UXFrame to your application, the navigation between pages will be displayed directly. The UXFrame control includes a dozen of predefined animation library which enables you to easily add stunning visual transitions to your navigation frame.
To enable transition between page navigation, set the EnablePageTransition property of the frame to true. When the page transition is enabled, you will notice a fading animation while navigating between pages.
The following example shows how to enable page transition to UXFrame.
XAML |
Copy Code
|
---|---|
<Intersoft:UXFrame Name="ContentFrame" EnablePageTransition="True"> </Intersoft:UXFrame> |
When the page transition is enabled, the UXFrame automatically apply the visual transition based on the navigation mode. You can set the visual transition to be applied differently for each navigation mode. The following table lists the basic properties related to visual transitions and its default values.
Property | Default Value | Description |
---|---|---|
BackTransitionEffect | FlipLeft | This transition will be applied when the frame is navigating backward. |
ForwardTransitionEffect | FlipRight | This transition will be applied when the frame is navigating forward. |
DefaultTransitionEffect | Fading | This transition will be applied when navigating to a new page, or when the navigation mode cannot be determined. |
You can choose one of the TransitionEffect to apply to your visual transition properties:
The following example shows how to customize the visual transitions for back, forward and new navigation mode.
XAML |
Copy Code
|
---|---|
<Intersoft:UXFrame Name="ContentFrame" EnablePageTransition="True" BackTransitionEffect="SlideLeft" ForwardTransitionEffect="SlideRight" DefaultTransitionEffect="FlipUp"> </Intersoft:UXFrame> |
By default, the visual transition is set to play for 0.3 seconds. You can customize how long the visual transition should play by setting the frame's TransitionDuration property to the desired value in seconds.
The following example shows how to customize the transition duration of the frame.
XAML |
Copy Code
|
---|---|
<Intersoft:UXFrame Name="ContentFrame" EnablePageTransition="True" TransitionDuration="1" BackTransitionEffect="SlideLeft" ForwardTransitionEffect="SlideRight" DefaultTransitionEffect="FlipUp"> </Intersoft:UXFrame> |
The recommended transition duration for a typical business application is between 0.3 and 0.7 seconds. You need to carefully review and evaluate your application's user experiences after applying the visual transition. Reducing or increasing the duration exceeding the above recommended value will often cause a poor user experience. |
UXFrame provides an advanced mechanism to automatically detect the direction of the current navigation process. Called AutoDetectNavigationDirection, this feature makes it easy for you to determine the position of the target destination relative to the current navigation position, which enables you to perform certain actions based on the navigation direction.
The following example shows how to enable automatic navigation direction feature.
XAML |
Copy Code
|
---|---|
<Intersoft:UXFrame Name="ContentFrame" EnablePageTransition="True" AutoDetectNavigationDirection="True"> </Intersoft:UXFrame> |
Once the feature is enabled, you can obtain the information of the navigation directions in the event data of the Navigating event, which is shown in the following example.
C# |
Copy Code
|
---|---|
void ContentFrame_Navigating(object sender, NavigatingCancelEventArgs e) { if ((e.FragmentNavigationDirection & FragmentNavigationDirection.Child) == FragmentNavigationDirection.Child) { if (e.UserNavigationDirection == NavigationDirection.New) { // do something } } } |
As seen in the above example, UXFrame exposes two kind of information related to the navigation direction, the FragmentNavigationDirection and the UserNavigationDirection property.
The core of this feature is the mechanism to determine the FragmentNavigationDirection of the current navigation process, and then map it to the UserNavigationDirection. The FragmentNavigationDirection is a Flag enumeration and can contain more than one value. The UserNavigationDirection property will be used to determine the final result of the current navigation process.
The following table shows several examples of the navigation requests, and how the FragmentNavigationDirection is determined and mapped to the navigation direction.
Current Navigation Path | New Navigation Path | Fragment Direction | Navigation Direction |
---|---|---|---|
/ or empty | / or empty | Root | New |
/ | /Customers | Child | Forward |
/Customers | /Products | CrossFragment | New |
/Products | /Products/Books | Child | Forward |
/Products/Books | /Products | Parent | Back |
/Products/Books | /Reports | CrossFragment | Parent | Back |
/Products | /Reports/Sales | CrossFragment | Child | Forward |
/Reports/Sales | / | CrossFragment | Root | New |
/Settings | / | Root | New |
Although the navigation direction can be automatically detected in most scenarios, there may be situations where the direction cannot be determined. In this case, both the FragmentNavigationDirection and UserNavigationDirection will be set to Unknown.
The automatic navigation direction detection feature is particularly useful when your application is designed with structured navigation topology. You can easily apply visual transitions based on the navigation direction result, which is calculated from the fragment direction described in the above section.
The navigation detection feature, when combined with the visual transitions, enables you to create visually compelling application with consistent user experiences. For example, navigating from parent to child will apply SlideLeft transition, while navigating from child to parent will apply the SlideRight transition.
When the automatic navigation direction feature is enabled, the visual transition properties such as BackTransitionEffect described in above section, are reused to provide streamlined settings for the visual transitions. Since the automatic detection feature uses a more advanced logic to determine the direction of the new navigation, certain transition properties may have different meaning.
The following table describes the new mapping between the navigation direction and transition properties when AutoDetectNavigationDirection feature is enabled.
Navigation Direction | Applied Transition Property |
---|---|
New | NewTransitionEffect |
Back | BackTransitionEffect |
Forward | ForwardTransitionEffect |
Unknown | DefaultTransitionEffect |
Notice that the DefaultTransitionEffect has different meaning when the detection feature is enabled. With the feature disabled, the DefaultTransitionEffect is applied for new navigation request. In contrast, the DefaultTransitionEffect is only applied for unknown direction when the AutoDetectNavigationDirection feature is enabled.
The following example shows how to setup the UXFrame to use the navigation detection feature and customize the related visual transition properties.
XAML |
Copy Code
|
---|---|
<Intersoft:UXFrame Name="ContentFrame" EnablePageTransition="True" AutoDetectNavigationDirection="True" NewTransitionEffect="ZoomIn" BackTransitionEffect="SlideLeft" ForwardTransitionEffect="SlideRight" DefaultTransitionEffect="Fading"> </Intersoft:UXFrame> |
In certain cases when automatic navigation detection is not suitable to your scenario, or you want to customize the transition based on your own logics, you can handle the ResolveNavigationDirection event of the frame, and set the resolved transition direction in the event data.
The following example shows how to programmatically customize the transition direction when the frame is navigating to a child fragment and the target navigation path is /Customers.
C# |
Copy Code
|
---|---|
private void ContentFrame_ResolveNavigationDirection(object sender, NavigationDirectionChangedEventArgs e) { if (e.NavigationMode == System.Windows.Navigation.NavigationMode.New) { string uri = e.Uri.ToString().ToLower(); if ((e.FragmentDirection & FragmentNavigationDirection.Child) == FragmentNavigationDirection.Child) { if (uri.Contains("customers")) e.ResolvedTransitionDirection = TransitionContentDirection.Replace; } } } |
UXFrame includes streamlined error management by providing a built-in friendly error page. When the navigation frame caught an exception that thrown during the navigation process, for instance, the page not found error, UXFrame shows a friendly error page instead of throwing a Javascript error message to the user.
The friendly error page looks like the following figure.
You can customize the error page with your own XAML template by setting the ErrorStyle property of the UXFrame control.
The following example shows the XAML template used to define the error page style of the navigation frame.
XAML |
Copy Code
|
---|---|
<Intersoft:UXPage ... > <Intersoft:UXPage.Resources> <Style x:Key="CustomErrorPageStyle" TargetType="Intersoft:UXFrameErrorPage"> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Stretch"/> <Setter Property="ErrorTextFormat" Value="Unable to navigate to '{0}'"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Intersoft:UXFrameErrorPage"> <Grid x:Name="LayoutRoot" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Background="White"> <Grid.ColumnDefinitions> <ColumnDefinition Width="81"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="64"/> <RowDefinition Height="5"/> <RowDefinition Height="34"/> <RowDefinition/> </Grid.RowDefinitions> <Image HorizontalAlignment="Center" Margin="0,15,0,1" Source="/Intersoft.Client.UI.Navigation;component/Resources/win7_error48.png" Stretch="None"/> <TextBlock x:Name="TitleElement" Grid.Column="1" Foreground="#FF903222" FontSize="16" Margin="1,0,0,10" TextWrapping="Wrap" Text="{TemplateBinding ErrorTitle}" VerticalAlignment="Bottom"/> <Border BorderBrush="#FFD0D0D0" BorderThickness="0,1,0,0" Grid.Column="1" Height="1" Margin="0,0,50,0" Grid.Row="1" VerticalAlignment="Center"/> <TextBlock Grid.Column="1" Foreground="#FF494949" FontSize="14.667" HorizontalAlignment="Left" Grid.Row="2" TextWrapping="Wrap" Text="More Information" VerticalAlignment="Center"/> <TextBlock x:Name="DetailElement" Grid.Column="1" Foreground="#FF4F4F4F" FontSize="12" Grid.Row="3" TextWrapping="Wrap" Text="{TemplateBinding ErrorDetails}" ScrollViewer.VerticalScrollBarVisibility="Auto"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </Intersoft:UXPage.Resources> ... <Intersoft:UXFrame x:Name="ContentFrame" EnablePageTransition="True" TransitionDuration="0.5" ErrorStyle="{StaticResource CustomErrorPageStyle}"> <Intersoft:UXFrame.UriMapper> ... </Intersoft:UXFrame.UriMapper> </Intersoft:UXFrame> ... </Intersoft:UXPage> |
The result of the customized error page is shown in the following figure.
One of the features in UXFrame that makes it a versatile navigation framework is the full support for nested child navigation. Child navigation refers to the use of UXFrame inside a page that already hosted by upper level of frames. More importantly, UXFrame supports browser journal integration for the child level navigation, which is not supported in Silverlight's built-in or other navigation frameworks.
Child navigation is particularly useful in line-of-business applications that require great usability and accessibility. For example, consider a master-detail scenario where you have a page that contains a list of customers and another page that shows the details of a customer. With child navigation, you can design the page in a way where the list and the details are displayed side-by-side. Consequently, users can navigate to the details page in consistent manner through various ways, such as through the UI selection, or through the journal history or direct address of the browser.
The following illustration shows the child navigation architecture.
As seen in the above illustration, the child navigation takes advantage of the URI mapping concept which allows a path segment to represent a different level of child navigation. For more information about the basics of navigation, URI mapping and navigation segments, see Navigation Overview.
The following list describes the important points and behaviors of the child navigation process:
Consider that you have a Silverlight application with three pages: MainPage.xaml, Customers.xaml and CustomerDetails.xaml. The MainPage.xaml is the root page of the application and contains the root UXFrame named ContentFrame. The Customers.xaml contains a list of customers data and another UXFrame named DetailsFrame. The CustomerDetails.xaml contains form controls and labels to display customer details.
In this scenario, the ContentFrame is the parent frame and the DetailsFrame is the child frame. Implementing your navigation application to use the child navigation feature generally involves three processes such as described in the following:
The following examples show how to implement child navigation using the master-detail scenario described above.
MainPage.xaml |
Copy Code
|
---|---|
<Intersoft:UXFrame x:Name="ContentFrame" AllowNestedFrameNavigation="True"> <Intersoft:UXFrame.UriMapper> <Intersoft:UriMapper> <Intersoft:UriMapping Uri="" MappedUri="/Views/Home.xaml"/> <Intersoft:UriMapping Uri="/Customers/{ID}" MappedUri="/Views/Customers.xaml" IsChildNavigation="True"/> <Intersoft:UriMapping Uri="/Error" MappedUri="/ErrorPage.xaml"/> <Intersoft:UriMapping Uri="/Register" MappedUri="/Views/Login/RegisterForm.xaml"/> <Intersoft:UriMapping Uri="/{page}" MappedUri="/Views/{page}.xaml"/> </Intersoft:UriMapper> </Intersoft:UXFrame.UriMapper> </Intersoft:UXFrame> |
An important point to note in the above example is how the UriMapping is defined to enable the child navigation to work properly. When designing the child navigation, you already have an outline how you want users to navigate to the pages. In this case, you design the navigation structure in a way that allows the customer details to be navigable from the second segment of the Uri. For instance, navigating to /Customers/SMITH will instruct the child navigation to respond the request and map the SMITH segment into the {ID} variable which can be accessed from the child page.
With the understanding of the child navigation process described above, you add a UriMapping with its Uri set to /Customers/{ID} which is mapped to the child page that responsible to process the request further. In this case, the MappedUri of the mapping should be set to Customers.xaml.
The logical order of the UriMapping definition in the UriMapper collection could produce different result when arranged incorrectly. The UriMapping whose Uri has more specific pattern should be placed prior to the other UriMapping with broader (or more general) pattern. |
The following example shows how to define the child frame to support browser's journal integration.
Customers.xaml |
Copy Code
|
---|---|
<Intersoft:UXFrame x:Name="DetailsFrame" DisplayFragmentInBrowser="True"> <Intersoft:UXFrame.UriMapper> <Intersoft:UriMapper> <Intersoft:UriMapping Uri="" MappedUri="/Views/CustomerDetails.xaml"/> <Intersoft:UriMapping Uri="/Customers/{ID}" MappedUri="/Views/CustomerDetails.xaml?ID={ID}"/> </Intersoft:UriMapper> </Intersoft:UXFrame.UriMapper> </Intersoft:UXFrame> |
As seen in the above example, it is required to set the DisplayFragmentInBrowser property of the DetailsFrame to true. In addition, the DetailsFrame uses the standard UriMapping implementation which maps the /Customers/{ID} request to /Views/CustomerDetails.xaml?ID={ID}. To learn more about the basic mapping and query string concept in navigation framework, see Navigation Overview.
The JournalOwnership property of the child frame should be set to Automatic, which is the default value. This property should not be changed to other values in order for the browser integration to work properly. |
The following illustration shows the child navigation workflow using the master-detail scenario described above.
For a guided walkthrough to implement child navigation, see Walkthrough: Configure Nested Navigation Frame to Support Browser-Journal Integration.
When a navigation occurred only at the child frame, the parent frame is not reloaded. The ClientUI navigation framework is designed this way to produce smooth user experiences. Since the parent frame is not reloaded, the navigation events for the parent frame are not raised. In certain cases, you need to track when the child page has changed and that the parent page needs to do certain actions, such as invalidating properties or assigning the data context.
ClientUI provides ChildNavigation routed event which is raised when a child page has been successfully navigated within the parent frame context. In most cases, you might be interested to handle the child navigation event in the page level instead of implementing the routed event in the frame level. This can be done by overriding the OnChildNavigation protected method of the UXPage class.
Using the master-detail scenario such as described in the previous section, the following example shows how to invalidate the data context when the page of the child frame has changed.
C# |
Copy Code
|
---|---|
public partial class Customers : UXPage { public MobilePhones() { InitializeComponent(); } protected override void OnNavigatedFrom(NavigationEventArgs e) { base.OnNavigatedFrom(e); } // Executes when the user navigates to this page. protected override void OnNavigatedTo(NavigationEventArgs e) { LoadData(this.NavigationContext.QueryString); } // Called when a child navigation has occurred. protected override void OnChildNavigation(ChildNavigationEventArgs e) { LoadData(e.QueryString); } ... } |
One of the benefits of using the OnChildNavigation method override in the UXPage is that you can easily obtain the QueryString of the current navigation context which is passed from the parent frame. Since the QueryString uses the same signature as in NavigationContext, you can refactor your code to be efficiently called from various entry points in the code.
ClientUI navigation framework includes built-in busy state management feature which helps to streamline the busy state implementation in your navigation application. You set the IsBusy property of the UXPage to true when the page is processing particular operations, such as asynchronous data retrieval from server. Likewise, you set the IsBusy property to false when the operation has completed.
The busy state management architecture is designed in such a way that intuitive to developers. The UXFrame automatically reacts when the active page propagates the changes of its IsBusy property. Consequently, this significantly reduces development effort by eliminating the needs to implement the busy indicator manually in each page.
With a single dependency property to handle the IsBusy state, this design is also an ideal solution for MVVM pattern development. You can easily bind the IsBusy property to your ViewModel and then execute the operation within your ViewModel.
The following example shows how to work with the busy state management feature in UXFrame and UXPage using the MVVM pattern.
RegisterForm.xaml |
Copy Code
|
---|---|
<Intersoft:UXPage ... xmlns:Intersoft="http://intersoft.clientui.com/schemas" xmlns:ViewModels="clr-namespace:ClientUIBusinessApp1.ViewModels" x:Class="ClientUIBusinessApp1.RegisterForm" IsBusy="{Binding Path=IsBusy}"> <Intersoft:UXPage.DataContext> <ViewModels:RegisterFormViewModel/> </Intersoft:UXPage.DataContext> <Grid x:Name="LayoutRoot"> ... </Grid> </Intersoft:UXPage> |
The following code shows the ViewModel of the RegisterForm that responsible to manage the busy state according to the business logic. Notice that the IsBusy property of the ViewModel is bound to the IsBusy property of the UXPage.
RegisterFormViewModel.cs |
Copy Code
|
---|---|
public class RegisterFormViewModel : ValidationViewModelBase { // Fields private bool _isBusy = false; // Views public bool IsBusy { get { return _isBusy; } private set { if (_isBusy != value) { _isBusy = value; OnPropertyChanged("IsBusy"); } } } // Methods private void ExecuteCreateAccount(object parameter) { if (this.Validate()) { // Enables the page's busy state. // This will block user interaction while the login // is being processed and optionally display busy indicator. IsBusy = true; // Perform asynchronous server-side call to create user account _registrationContext.CreateUser(this.RegistrationData, this.RegistrationData.Password, this.SelectedRoles, CreateAccount_Completed, null); } else { this.FocusErrorField(); } } ... } |
For more information about application development with MVVM pattern, see MVVM Pattern Overview.
In most cases, you may want to block the user interface from being accessible by users when processing a longer operation such as data loading or updating. To do this, you simply set the BlockUIOnBusy property of the page to true.
With BlockUIOnBusy enabled, the user interface elements such as text boxes, buttons and other input controls will be automatically disabled when the IsBusy property of the page is set to true. In addition, the cursor will indicate a busy state for the page region which complies to usability standards. For more information about user experience standards implementation in ClientUI, see User Experiences Overview.
The following example shows how to setup the page to block the user interaction when busy.
XAML |
Copy Code
|
---|---|
<Intersoft:UXPage ... xmlns:Intersoft="http://intersoft.clientui.com/schemas" xmlns:ViewModels="clr-namespace:ClientUIBusinessApp1.ViewModels" x:Class="ClientUIBusinessApp1.RegisterForm" IsBusy="{Binding Path=IsBusy}" BlockUIOnBusy="true"> <Intersoft:UXPage.DataContext> <ViewModels:RegisterFormViewModel/> </Intersoft:UXPage.DataContext> <Grid x:Name="LayoutRoot"> ... </Grid> </Intersoft:UXPage> |
To enhance the user experiences when using busy state feature, you can customize the latency that determines how long a time span should elapse before the busy indicator is displayed. This feature is particularly useful to avoid user interface flickering that may occur when the busy state is changed too fast. For example, consider the scenario when you click a button to load an item's details which subsequently displays the busy indicator. However, the data may load faster than expected specifically when the network traffic is low. This causes flickering as the busy indicator is shown and hidden immediately.
You set the BusyIndicatorLatency property of the UXFrame to a time span measured in seconds. The default value is 1 second, which means that only operations longer than 1 second will show the busy indicator and process the user interface blocking, if BlockUIOnBusy feature is enabled.
Note that the feature is designed at the UXFrame level to provide consistent user experience throughout all the pages in the application. This also eliminates the need to set the value individually at each page, which could be a tedious task.
The following example shows how to customize the busy latency of the frame to 0.8s.
XAML |
Copy Code
|
---|---|
<Intersoft:UXFrame x:Name="ContentFrame" BusyIndicatorLatency="0.8"> <Intersoft:UXFrame.UriMapper> ... </Intersoft:UXFrame.UriMapper> </Intersoft:UXFrame> |
The recommended value for BusyIndicatorLatency for an acceptable user experiences is between 0.7 to 1.3 seconds. |
To display the user interface that represents busy indicator, you define the XAML template to apply to the BusyIndicatorTemplate of the navigation frame. Similar to the BusyIndicatorLatency described in the above section, this feature is designed at the frame level to provide consistent user experience throughout the application.
The following example shows how to customize the busy indicator template to display an indeterminate progress bar during busy state.
XAML |
Copy Code
|
---|---|
<Intersoft:UXPage.Resources> <DataTemplate x:Key="FrameBusyTemplate"> <Grid Opacity="0.8"> <Border BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center" CornerRadius="8" Background="Black"> <Intersoft:UXProgressBar HorizontalAlignment="Left" Width="150" Height="18" IsIndeterminate="True" Margin="20"/> </Border> </Grid> </DataTemplate> </Intersoft:UXPage.Resources> ... <Intersoft:UXFrame x:Name="ContentFrame" BusyIndicatorTemplate="{StaticResource FrameBusyTemplate}" BusyIndicatorLatency="0.8"> <Intersoft:UXFrame.UriMapper> ... </Intersoft:UXFrame.UriMapper> </Intersoft:UXFrame> |
The following figure illustrates the busy state management with customized template.
To learn more about the progress bar control and its features, see UXProgressBar.
In many line-of-business scenarios, your application may require certain pages to authenticate against the current user. ClientUI navigation framework includes built-in authentication feature which is implemented at the core navigation process in the UXFrame and UXPage class. This ensures high security protection as the authentication process is built into the framework, which eliminate the need of additional workaround or plumbing code.
At the core of the authentication feature in ClientUI navigation framework is the User property, which is exposed in the UXPage and UXFrame class. In most cases, you assign the User property of the UXFrame to enable single sign-on scenario in your application. The User property in the UXPage allows you to build more advanced applications where certain pages may require separate authentication from different authentication provider.
To implement authentication, you set the User property of the frame to an object that implements IPrincipal interface. Since the User property relies on IPrincipal interface which is implemented in the Silverlight runtime, the authentication feature in ClientUI navigation framework allows you to flexibly use any kind of authentication providers such as WCF Authentication Service, or other third party's authentication services. For scalable authentication implementation that produces consistent result, it is recommended that you use MVVM pattern to maintain the user authentication, which is generally achieved by binding the User property to an authentication context defined in ViewModel.
Once you have defined the User property, you can easily set the pages of which the authentication is required by setting the RequiresAuthentication property of those pages to true. Role-based security is also supported through the same authentication context that implemented in the User property. To enable authentication against users with particular roles, set the RequiresRole property of the UXPage to the desired roles.
If your page requires multiple roles to be accessible, you can specify multiple roles with each role separated by a comma, i.e, "Administrators, Product Managers". |
When UXFrame navigates to a page with RequiresAuthentication property enabled, the authentication context in the User property that implements IPrincipal will be used for query. If the User was determined as authenticated, the page will be displayed as normally. Otherwise, the UXFrame will redirect to the Uri defined in the RedirectUri property for login if specified, or raise a NavigationFailed event when the redirection is not handled.
The authentication events, lifetime and workflow is described in the following figure.
ClientUI Framework provides four routed events related to authentication service which are currently raised by UXFrame class. The authentication routed events are:
If the RequestingAuthentication event is not handled and the RedirectUri is not specified, the UXFrame will raise NavigationFailed event for the particular navigation request. |
For the Authenticated, LoggedIn and LoggedOut event to work properly, the object that represents the authentication service which you bind to the User property, should be implemented on a class that implements INotifyPropertyChanged interface. The target property that you bind to, which implements the IPrincipal interface, should implement the INotifyPropertyChanged interface as well. One of the authentication services that satisfy these requirements is WCF Authentication Service, which is explained in the following section.
For more information about routed events, see Routed Events Overview.
This section describes the important concepts in using WCF Authentication Service as the authentication provider for the ClientUI navigation framework. For a step-by-step walkthrough in implementing authentication using WCF Authentication Service, see Walkthrough: Enable Authentication and Role-based Security to a Page using WCF Authentication Service.
WCF Authentication Service is based on the WCF RIA Services, which is a free add-on for developers as part of Visual Studio 2010 for Silverlight Tools. For more information about the download instruction and other required system components, see System Requirements.
As described in the above section, the WCF RIA Services provide authentication service that satisfies the implementation required by the ClientUI navigation framework. The service provides a server-side authentication that perform queries against the users and profiles table in SQL database which typically use ASP.NET default database. In addition, the service automatically generates the entities and types in the Silverlight project which can be consumed and implemented directly by the ClientUI navigation framework.
Before you can bind the User property to the WebContext in XAML, you need to add the current WebContext object to the application's resource during startup, such as shown in the following example.
C# |
Copy Code
|
---|---|
private void Application_Startup(object sender, StartupEventArgs e) { // Add the WebContext object to Resources so they can be bound to the controls in XAML files this.Resources.Add("WebContext", WebContext.Current); // Set the root visual for the application this.RootVisual = new MainPage(); } |
The following example shows the XAML code to bind the User property of the frame to the User object of the WebContext which is generated by the WCF Authentication Service.
XAML |
Copy Code
|
---|---|
<Intersoft:UXFrame x:Name="ContentFrame" User={Binding User, Source=WebContext}> <Intersoft:UXFrame.UriMapper> ... </Intersoft:UXFrame.UriMapper> </Intersoft:UXFrame> |
The following example shows how to setup a UXPage to require user authentication.
XAML |
Copy Code
|
---|---|
<Intersoft:UXPage xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:Intersoft="http://intersoft.clientui.com/schemas" RequiresAuthentication="True" ...> </Intersoft:UXPage> |
The following example shows how to setup a UXPage to require user authentication with particular roles.
XAML |
Copy Code
|
---|---|
<Intersoft:UXPage xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:Intersoft="http://intersoft.clientui.com/schemas" RequiresAuthentication="True" RequiresRole="Administrators" ...> </Intersoft:UXPage> |
Intersoft ClientUI includes a Visual Studio 2010 project template that leverages the authentication and many advanced features available in ClientUI navigation framework, as well as built-in integration with WCF Authentication Service using MVVM pattern. The project template also includes comprehensive login functionality and a rich registration form. To learn how to create navigation applications based on this template, see Introduction to ClientUI Project Templates. |
ClientUI provides single sign-on authentication to streamline the authentication implementation in line-of-business navigation applications. With single sign-on, the pages that require authentication share the same user authentication context. This allows the user to be authenticated one time for all the pages in the application.
To facilitate the single sign-on authentication mechanism, ClientUI provides an application framework that designed with shell pattern which is centered around UXShell class. The UXShell acts as a lightweight container that provides a variety of application management services, including a solid integration with authentication service that can be consumed from many high-level components such as the navigation and window components. For more information about the application framework in ClientUI, see Application Framework Overview.
Since a single ClientUI application generally instantiates only one instance of UXShell, you can think of UXShell as a generic model that represents your entire application. This allows you to access the UXShell services consistently throughout your pages by using data binding as well as MVVM pattern.
To implement single sign-on authentication, you bind the authentication context to the UXShell object instead of binding to the UXFrame which described in the above section. Consequently, you bind the User property of the UXFrame to the UXShell object that exposed through static resource.
The following examples show the steps to implement single sign-on authentication.
Prior to the data binding in XAML, you create a UXShell instance in the App.xaml which is then added to the application's resource during startup, which is shown in the following example.
C# |
Copy Code
|
---|---|
public App() { this.Startup += this.Application_Startup; this.Exit += this.Application_Exit; this.UnhandledException += this.Application_UnhandledException; InitializeComponent(); InitializeShell(); } private void InitializeShell() { // Create a WebContext and add it to the ApplicationLifetimeObjects // collection. This will then be available as WebContext.Current. WebContext webContext = new WebContext(); webContext.Authentication = new FormsAuthentication(); this.ApplicationLifetimeObjects.Add(webContext); // Create a Shell and setup its RootApplication UXShell shell = new UXShell(); shell.RootApplication = UXShell.CreateApplicationFromType(typeof(App), ApplicationID, ApplicationID); // Bind WebContext's User to the Shell, so we can enable single sign-on login feature // and many other integrated features to easily query the authenticated user. shell.CreateBinding(UXShell.UserProperty, "User", webContext); // Add the shell to the ApplicationLifetimeObjects collection. this.ApplicationLifetimeObjects.Add(shell); } private void Application_Startup(object sender, StartupEventArgs e) { // Add the objects to Resources so they can be bound to the controls in XAML files this.Resources.Add("WebContext", WebContext.Current); this.Resources.Add("Shell", UXShell.Current); this.RootVisual = new MainPage(); } |
In the above example, notice that object initialization such as the creation of WebContext and UXShell is executed in the constructor of the App class. It is important to note that the User property of the WebContext is actually bound to the UXShell through the CreateBinding method.
The following example shows how to setup the UXFrame to bind the User property to the UXShell object which was configured in the previous code.
XAML |
Copy Code
|
---|---|
<Intersoft:UXFrame x:Name="ContentFrame" User="{Binding User, Source={StaticResource Shell}}" RedirectUri="/Login"> <Intersoft:UXFrame.UriMapper> ... </Intersoft:UXFrame.UriMapper> </Intersoft:UXFrame> |
With the authentication context bound to the UXShell that implements IApplicationService, you can reliably consume many of the application services, such as the authentication service, in any number of pages in your application. In addition to authentication, UXShell provides more advanced features such as application lifetime management and navigation to external application package (.xap) on-demand. For more information, see Application Framework Overview.
For a complete step-by-step walkthrough to create business navigation application using ClientUI navigation framework, see Walkthrough: Create Line-of-Business Navigation Application using MVVM Pattern.
In certain cases, you may want to have certain pages that do not participate with the single sign-on authentication. To do this, you set the UseSingleSignOn property of the particular page to false, then bind the User property of the page to a different authentication context. |
With the nature of Silverlight and WPF as a client-side platform, the user authentication is typically performed through an asynchronous callback to the server-side through web services such WCF RIA Services. In most cases, you want to prevent users to interact with your application while authentication is in progress, such as when login or logout operation is being performed.
UXFrame streamlines the authentication process by providing IsAuthenticating property, which makes it easy for you to track when authentication process is being executed. You can use MVVM pattern to manage this property in your ViewModel.
When the IsAuthenticating property is set to true, UXFrame automatically blocks the page from user interactions thus preventing users to work with the page while the authentication operation is in progress. More importantly, the UXFrame will hold the current navigation request until the authentication process is completed, which is indicated by the IsAuthenticating property set to false. This behavior is designed to ensure consistent user experience in real-world applications that leverage authentication over the web service.
The following example shows how to implement IsAuthenticating property using MVVM pattern to track and control the authentication progress.
XAML |
Copy Code
|
---|---|
<Intersoft:UXFrame x:Name="ContentFrame" User="{Binding User, Source={StaticResource Shell}}" IsAuthenticating="{Binding IsAuthenticating, Source={StaticResource Shell}}" RedirectUri="/Login"> <Intersoft:UXFrame.UriMapper> ... </Intersoft:UXFrame.UriMapper> </Intersoft:UXFrame> |
The following example shows how to perform user authentication during application startup and controls the IsAuthenticating property to take advantage of the built-in busy state management.
C# |
Copy Code
|
---|---|
private void Application_Startup(object sender, StartupEventArgs e) { // Automatically authenticate a user when using windows authentication // or when the user chose "Remember me" on the previous login attempt. WebContext.Current.Authentication.LoadUser(this.Application_UserLoaded, null); // Since auto login is performed asynchronously at startup, it's important to ensure the // navigators such as UXFrame to delay the navigation process until the authentication is done. UXShell.Current.IsAuthenticating = true; } private void Application_UserLoaded(LoadUserOperation operation) { // Auto authentication is completed UXShell.Current.IsAuthenticating = false; } |
One of the advanced features in ClientUI navigation framework is the seamless integration with the application framework to provide navigation capability to the external application package using the same semantics and API used in the navigation framework. As a result, you can rapidly create composite navigation application that capable to navigate to pages in an external package without writing extensive code.
For more information on how to navigate to external application packages using ClientUI navigation framework, see ClientUI Application Services.
For more information about the ClientUI application framework and its fundamental architecture and concepts, see Application Framework Overview.
This section provides links to the related topics on using the ClientUI navigation framework.
How-to: Navigate to a Page using Command
How-to: Configure URI Mapping using Type Name
How-to: Navigate to a Page with Extra Data
How-to: Navigate Forward Through Navigation History
How-to: Navigate Backward Through Navigation History
How-to: Stop a Page from Loading
More walkthroughs and how-to topics are available in Navigation Walkthroughs and Navigation How-to Topics respectively.