Friday, June 20, 2008

Enabling browser back button in Silverlight 2 beta 2

Who hasn't encountered the problem of not being able to use the browser buttons when navigating a Flash, Silverlight or AJAX enabled website?
This articles describes how you can prevent this in your Silverlight application.

In this article I will explain how to use a class created by Mark Rideout for his TechEd presentation during this year's TechEd in the US.

1. Implement the NavigationManager


Include the NavigationManager.cs in your Silverlight application.
You can find it in the sourcecode of the project (see below).

Now implement the INavigationState interface on you main Silverlight UserControl(usually the Page UserControl).
public partial class Page : UserControl, INavigationState

#region INavigationState Members

public NavigationPropertyDictionary GetState()
{
throw new NotImplementedException();
}

public void LoadState(NavigationPropertyDictionary properties)
{
throw new NotImplementedException();
}

public string Id
{
get { throw new NotImplementedException(); }
}

#endregion

2. Instantiate the NavigationManager in the constructor


NavigationManager.Instance.Register(this);            
NavigationManager.Instance.LinkingMode = NavigationManager.LinkMode.None;

3. Declare a page indexer field and set it


This field is saved in the state of the NavigationManager so you know which page to show.
private int _pageIndex=-1;

On a state change, set the value of the page indexer field and save the current state:
_pageIndex = 1;
HtmlPage.Document.SetProperty("title", "Page 1");
NavigationManager.Instance.Save();


Now do this for all the state changes you want to have in your browser history:

_pageIndex = 2;
HtmlPage.Document.SetProperty("title", "Page 2");
NavigationManager.Instance.Save();

4. Create code for GetState()


When implementing the interface a number of methods were created.
The GetState() method sets the index of the NavigationPropertyIndex to the pageindex used in this example:

public NavigationPropertyDictionary GetState()
{
NavigationPropertyDictionary props = new NavigationPropertyDictionary(this);
props["index"] = _pageIndex.ToString();
return props;
}

5. Create code for LoadState


The retrieval of the pages from the state need to be implemented in this method.
By using the NavigationPropertyDictionary's index property we are able to retrieve the current index:

public void LoadState(NavigationPropertyDictionary properties)
{
ContentPlaceholder.Children.Clear();

if (properties.Count > 0)
{
UserControl pageToLoad = new UserControl();
switch (int.Parse(properties["index"]))
{
case 1:
HtmlPage.Document.SetProperty("title", "Page 1");
pageToLoad = new Subpage1();
break;
case 2:
HtmlPage.Document.SetProperty("title", "Page 2");
pageToLoad = new Subpage2();
break;
case 0:
HtmlPage.Document.SetProperty("title", "Home");
break;
default: break;
}
ContentPlaceholder.Children.Add(pageToLoad);
}
}

6. Create code for the ID property


This property is used for naming the ParentStateID in the NavigationManager. You'll also see this name in the querystring (depending on the settings).

public string Id
{
get { return "home"; }
}

7. Optional setting; LinkingMode


The property available on the NavigationManager which enables the address bar to be updated as well. So the querystring is set to the value necessary for deeplinking.
To set the LinkingMode property use the following code:
NavigationManager.Instance.LinkingMode = NavigationManager.LinkMode.None;


Click here for the demo

Click here for the source

4 comments:

  1. Looks neat - very useful bit of code... but when trying the demo using Firefox (3), I found each page appeared twice in my history, requiring me to click the back buton twice to go back one page...?

    ReplyDelete
  2. Hi Nick,
    Thanks, Mark Rideout did the work, I just work an explanation. All compliments go to him for producing the code.
    I've just tested it with Firefox 2 and it seems to be working fine. I already tried FF3 and I didn't notice this problem. Tomorrow at work I'll try FF3 again to see if the problem occurs in there.

    ReplyDelete
  3. I tried the demo in Firefox 2, each page appeared twice in history too....

    ReplyDelete
  4. hi,
    I tried in Firefox 3.5 but not working

    ReplyDelete