Silverlight Page Navigating with MVVM Light Messaging and Songhay NavigationBookmarkData
While Silverlight was deep in the cryogenic freezer in Redmond in the Windows-8-summer of 2012, I was working on my minimalist masterpiece, GenericWeb Editor (see screenshot). This editor (an internal tool) replaces the work I sold (by work-for-hire) to UCLA, dating back to before 2009—when I was not using Silverlight in any serious way. In those days, I was web-page centric—so the Silverlight/WPF concept of the Navigation Page was very welcome. The problem is that, apart from the default “Silverlight Navigation Application,” there is not much guidance in this area.
My design goals center around this strong point: any Navigation Application has to know about the locations/indicators in its domain. This implies that there are known Navigation locations and unknown locations. There are two types of known indicators: keys and patterns. My intent is to make Navigation data-centric—data-driven… So I’ve made for myself the NavigationBookmarkData
class to express this intent. This class defines the following conventions:
Get Data Format |
A pattern for getting data by a unique identifier: |
New Data Format |
A pattern for adding data: |
Delete Confirmation Key |
A key for the conventional application Delete Confirmation: |
Entity Association Selection Key |
A key for the conventional application Entity Association Selection: |
Entity Associations Key |
A key for the conventional application Entity Associations: |
Error Message Key |
A key for the conventional application Error Message : |
Index Key |
A key for the conventional application Index: |
Information Message Key |
A key for the conventional application Information Message : |
Search Key |
A key for the conventional application Search: |
Using NavigationBookmarkData
All Navigation commands are ‘tested’ by NavigationBookmarkData
to determine whether the Navigation location exists. Passing NavigationBookmarkData
tests means that a Bookmark is found and a call to HtmlPage.Window.NavigateToBookmark(bookmark)
can be made. In my early designs, I would have considered a call to NavigateToBookmark
as ‘indirect’—why can’t I touch the Navigation Frame directly? Calling out to the HtmlPage.Window
is indeed the start of round trip from the internals of the Silverlight application out to the hosting Web browser and then back to the Silverlight application. Why do this? I do this because this design makes “deep linking” in Silverlight possible. This design has only one way to handle Navigation commands: through changing the “hash tag” of the browser location—classic, Web 2.0, single-page-app navigation.
Navigation Frame Eventing
My Generic Web Editor Navigation Frame handles the Frame.Navigating
event by sending an MVVM Light message of type LightNavigationMessage<NavigatingCancelEventArgs>
. This event is fired by typing in a hash location in the browser or by an internal Navigation command. My conventional LightNavigationMessage<T>
checks the location to determine whether it is “well formed”; when it is well-formed then the location is parsed. The message is received in the Client View Model like this:
Messenger.Default.Register<LightNavigationMessage<NavigatingCancelEventArgs>>(this,
message =>
{
if(!message.IsExpectedMessage(LightMessageSource.View, "ClientFrame")) return;
this.HandleClientNavigating(message);
});
The HandleClientNavigating()
routine uses LightNavigationMessage<NavigatingCancelEventArgs>
to either cancel the navigation (with the reference to NavigatingCancelEventArgs
) or use the parsed data in the message to invoke a command in the application. It is important to point out that the code I am writing is still not doing any explicit Navigation Page handling. When a Navigation message is received, a command (like a RIA operation, calling the server) is invoked. It is the Silverlight UriMapper
that handles Navigation. My UriMapper
looks like this:
<navigation:Frame.UriMapper>
<uriMapper:UriMapper>
<uriMapper:UriMapping Uri="" MappedUri="/Views/IndexPage.xaml"/>
<uriMapper:UriMapping Uri="/" MappedUri="/Views/IndexPage.xaml"/>
<uriMapper:UriMapping Uri="/{key}/{id}" MappedUri="/Views/{key}Page.xaml"/>
<uriMapper:UriMapping Uri="/{key}" MappedUri="/Views/{key}Page.xaml"/>
</uriMapper:UriMapper>
</navigation:Frame.UriMapper>
The UriMapper
has a conventional relationship with the NavigationBookmarkData
Bookmark keys thought the declaration of the {key}
placeholder above. It follows that the same key is used to display a page and invoke an application command thought this loose convention.
Yes, it can get more complicated…
In the spring of 2012, I was working on the Silverlight BiggestBox, my personal teaching/practice tool for Silverlight. Because of MEF (and inexperience) I developed a more complication Navigation strategy. I touched upon this in “Implementing INavigationContentLoader with an abstract class…” I would like to take some the ideas shared here and revisit the BiggestBox.
Related Resources
Some history from Martin Mihaylov (2009)… There’s a very well-done explanation of | |
“While working recently on a navigation application, there was this requirement for animated page transitions. Moving from one page to another must look pretty and if possible should include advanced animations with pages flying in, fading out, etc.” “So I started investigating if and how this was possible with the navigation framework. And the answer is that it is very, very easy and it does not require a single line of code.” This solution uses the | |
“Typically, you use the | |
Thanks for asking, yes, I use | |
This 2009 Dino Esposito is a great overview of this Silverlight Toolkit control. I mention it here because I notice that a | |
“Silverlight 3 Navigation: Navigating to Pages in referenced assemblies” |
“Dividing your pages across multiple assemblies doesn’t have to degrade user experience, and once you’re familiar with the style of URI that the navigation framework expects for such pages, it’s no more complex than standard navigation within your Silverlight application.” |
“Silverlight 3 Navigation framework with on demand assemblies” |
“The Silverlight 3 Beta of Navigation does not support on-demand loaded assemblies. You could load data, services, and things like that, but XAML pages must be in the DLLs that are packaged in the XAP for the Frame control to find them.” |
Shawn Wildermuth in 2008: “So the lesson learned here is to use | |
This might have changed since Silverlight 2: “…I decided to have another look at |