FINALLY!!!! I’ve had the code for the post ready to go for quite some time, I just haven’t had time to write it up properly due to a number of external commitments.
(If you’re new to this series I recommend catching up on the first set of posts here.)
In my last post I built out the mapping portion of the Silverlight browser. In this post I’ll build out the Navigation and History management pieces of the browser. This post is the entire reason I started this little experiment. Let me give you a little background in case you haven’t been following the series.
There are two features in Silverlight 3 that I’m excited about. The first is the Out of the Browser experience (don’t you dare call it SLOOB, seriously just don’t). This allows you to install* Silverlight apps onto a client machine that can run outside of the browser* in a disconnected mode.
*install – It doesn’t install in the typical sense, you won’t see anything in add/remove programs. It places a shortcut on your desktop and/or your programs menu. This shortcut then calls a launcher to get things up and running.
*outside of the browser – While the app isn’t technically running in Firefox, IE, etc. it is still operating in a browser sandbox, which means no direct access to the local system.
The second feature I’m excited about is the navigation framework. This framework allows you build structured apps that can levergate the browsers history and navigation functionality to make moving around your app more intuitive for your users. Additionally, this framework allows you to leverage things like deep linking and SEO for your Silverlight apps. Pretty dang cool if you ask me!
The problem is when you marry these two features, that is build a navigation app that can run out of the browser. Once you take the app out of the browser, your user no longer has access to things like the forward and back buttons, the address bar, history, favorites, etc. Since Silverlight is all about great and consistent user experience (UX), this is problem is a major shortcoming. This project attempts to bridge the gap.
OK, enough rambling, let’s get to the code. I started off by adding the Silverlight.Navigation.History project to our solution. Here’s what the project looks like:
There’s nothing too complex, but here’s a brief description of each class:
HistoryItem. This represents a page/control/whatever you’ve navigated to within the application. There are only two properties, a uri (where the thing is) and a timestamp (when you went there).
HistoryItemCollection. Yup, you guessed it, this simply a collection of HistoryItem objects. There are a handful of methods in here that return items based on date (i.e. today, this week, last week, etc.), but that’s really it.
HistoryItemComparer. This is a helper class used by HistoryItemCollection. It implements IEqualityComparer<T> to compare HistoryItems. I implemented this class because I wanted the methods in HistoryItemCollection to only return distinct HistoryItem objects by uri. So the Equals method of this class simply inspects the uri’s of two objects to determine equality.
HistoryManager. This is an abstract class that is responsible for managing an application’s history. This class provides mechanisms for adding and removing items for history as well as getting all items for the application’s current session. This class also defines abstract Save and OnLoad methods which inheritors are responsbile for implementing. The intent of these methods is to read and write to the inheritors choice of peristent storage.
IsolatedStorageHistoryManager. This is a concrete implementation of the HistoryManager class. This class saves and loads history to and from isolated storage. Nothing tricky about it.
Now that we have our objects in place, let’s take a look at the controls. The first thing I did was to start playing around with the NavigationToolbar control. Here’s how it looks now:
The first thing you’ll see is a Back and Forward button. These are akin to the same buttons you’re used to using in the Internet browser of your choice. As you start to move around the Silverlight application these buttons will become enabled/disabled appropriately. To make this happen I simply hook into the Browser control’s NavigationFrame Navigated event set the properties based on the NavigationFrame CanGoBack and CanGoForward properties.
Next you’ll see a ComboBox that contains a list of all uri’s the user has visited during the current session, with the current uri selected. This data comes from the HistoryManager class discussed above. (As I write this I realize I intended this to be a smart combobox, allowing users to type in uri’s, but I only implemented a simple combobox. I’ll need to address this in a future release.)
Finally we have the History button. This will pop-up a window that display all the uri’s a user has visit during their multiple uses of the application. Once again, this data is provided by the HistoryManager class. This control also allows the user to clear history. Notice, I didn’t implement a confirmation when you clear history? This was intentional. Read the book Why Software Sucks and What You Can Do About It <<INSERT LINK>> to find out why.
To make all this work is pretty simple:
In my demo project’s Application_Startup event handler, I just instantiate a new HistoryManager object (in the case of the demo we’re using the IsolatedStorageHistoryManager object) and provide that to the constructor of the Browser object along with ApplicationMap. Here’s what we get when running out of the browser:
(Notice the Back and Forward buttons are enabled. Also we have a list of uri’s we’ve visited during the app’s current session.)
(Here we see the app’s history.)
I’ve issued a new release on the CodePlex site for this project that contains the functionality discussed above. You can download the release here.
I’ve also updated the app up on my website here. Per Tim Heuer’s post on Silverlight 3 beta install guidance, I customized the install experience to let folks know if they need Silverlight 3 and what it means to install the beta version of Silverlight 3 at this point in time.
Next up I’ll build out a way to manage favorites.