Navigation in Silverlight Without Using Navigation Framework

Silverlight 3 introduces Navigation Framework which takes care of this, but let's first try to achieve navigation and state management without this framework; or you can say, the way it is done in Silverlight 2.



Introduction:

In traditional ASP.NET, client applications are built around different web pages that encapsulate distinct tasks and in order to create this sort of application in Silverlight, we have a couple of ways to do that.

Silverlight 3 introduces Navigation Framework which does this for us, but let's first try to achieve navigation and state management without this framework; or you can say, the way it is done in Silverlight 2.

Step 1: Creating Silverlight Project

image1.gif

Create a Silverlight Application; here kindly note we are not using Silverlight Navigation Application, which we will do in next demo.

Give a solution and project name and click OK.

image2.gif

This window asks you where and how you want to host your application, Click Ok to accept the default values.

image3.gif

You Project will look similar to this.

Step 2: Understand the Logic

Instead of using navigation framework as stated earlier, we will do it ourself by directly manipulating the user interface. For example, you can use code to access the root visual, remove the user Control that represents the first page, and add another user control that represents a different page. This technique is straightforward, simple, and requires relatively little code. It also gives you the ability to micro-manage details like state management, which we will see later in a demo.


The basic technique is to use a simple layout container like Grid or Border as your application's root visual. You can then load user controls into the root visual when required and unload them afterward.

Go to App.xaml and notice which root visual element is first loaded,

image4.gif

The trick is to use something more flexible – a simple container like the border or a layout panel like the grid. Here's an example of the latter approach:

image5.gif

I have created a grid as my visual root element and added MainPage as its child. The grid is a container and we first cleared it, and added MainPage into its container collection as below.

private void Application_Startup(object sender, StartupEventArgs e)
        {
            //this.RootVisual = new MainPage();
            this.RootVisual = rootGrid;
            rootGrid.Children.Clear();
            rootGrid.Children.Add(new MainPage());
        }


Now the idea is simple; when we need to switch to another page, all we need to do is to add that page into a container collection of grid.

i.e.
rootGrid.Children.Add(new Page1());

so let's do it in a more systematic way. We will create a static method in App.xaml.cs file:

image6.gif

You see Navigate function take page as UserControl input which is where user want to navigate.

Before we add this page in container collection of grid, we need to take the current application object and cast it to an instance of custom App Class. This was not required before, because we were in Application_Startup event.

public static void Navigate(UserControl newPage)
        {
            App currentApplication = (App)Application.Current;
            currentApplication.rootGrid.Children.Clear();
            currentApplication.rootGrid.Children.Add(newPage);
 
        }


Now, Lets Test this. Create a button on MainPage.xaml and add a usercontrol; say Home.xaml:

image7.gif

Create a button on main.xaml

image8.gif

For click event on this button, just add the following code;

private void btnNavigate_Click(object sender, RoutedEventArgs e)
        {
            App.Navigate(new Home());
                    }

Home.xaml, create a textbox and a button to navigate back.

image9.gif

You are ready; hit F5 and see the result like below:

image10.gif

Click button to go to Home Page.

image11.gif

Step 3: How to manage the state of page.

Let's repeat the above step. Hit F5 and go to Home page and change the text in textbox and come back to MainPage and again go to Home page. You will notice that it does not retain the last message you posted; instead it's showing it's default message.

image12.gif

image13.gif

Notice here, that it always shows it's default message instead of the message we are writing; i.e. it's not retaining it's state.

To implement state management let us begin by implementing a system to identify pages. You could fall back on string names, but an enumeration gives you better error prevention. Here's an enumeration that distinguishes between three pages; let's say in our case, it is Home.xaml, Product.xaml and MainPage.xaml.

Come back to App.xaml.cs and create an enum.

public enum Pages
        {
                Mainwindow,
                ReviewPage,
                AboutPage       
        }

You can then store the pages of your application in private fields in your custom application class. Here's a simple dictionary that does the trick:

private static Dictionary<Pages, UserControl> PageCache = new Dictionary<Pages, UserControl>();
image14.gif

What also we are doing is creating cache memory with this simple dictionary, and creating a page only if they are requested for the first time else just navigating to that page. Only one version of the page is ever created, and it's kept in memory over the lifetime of the application.

We will keep our Navigate method and create a similar method as below.

public static void NavigateWithState(Pages newPage)
        {

             App cuurentApp = (App)Application.Current;
            //Check whether this page has been created before or not
            if (!PageCache.ContainsKey(newPage))
            {
                // Create the first instance of the page,and cache it for future use.
                Type type = cuurentApp.GetType();
                //Create Assembly of this type
                Assembly asm = type.Assembly;
                //Add into dictionaty , after casting it of UserControl Type
                PageCache[newPage] = (UserControl)asm.CreateInstance(
                        type.Namespace + "." + newPage.ToString());
            }
            //Navigate to this page
            cuurentApp.rootGrid.Children.Clear();
           cuurentApp.rootGrid.Children.Add(PageCache[newPage]);

        }

To use Assembly Class, add the following namespace.

using System.Reflection;

Now we are ready to run this application, but we will navigate using our new NavigateState Method which will maintain state, so let's amend the click events of button on MainPage.xaml and Home.xaml and let's add one more new usercontrol, Product.xaml.

On MainPage.xaml, edit click event as below.

private void btnNavigate_Click(object sender, RoutedEventArgs e)
        {
            App.NavigateWithState(App.Pages.Home);

        }

        private void btnNavigate1_Click(object sender, RoutedEventArgs e)
        {
            App.NavigateWithState(App.Pages.Product);
        } 

On Product and Home page ,edit click event as below ;

private void btn1_Click(object sender, RoutedEventArgs e)
        {
            App.NavigateWithState(App.Pages.MainPage);
        }


Hit F5, and see the screen as below.

image15.gif

Click to go to product page and change the text there.

image16.gif

image17.gif

Go back to main page and again click to go to product page; you will notice that our last posted message remained while we navigated among pages, which is now stateful navigation.

Conclusion:

In this article we understood, how to achieve navigation technique without using navigation framework, rather using some tricks and how to create single version of the page which is kept in memory over the lifetime of the application,

In next article, we will learn how to create model window application.

Cheers!