by StefanOlson via Stefan Olson's Blog on 6/3/2009 3:34:25 PM
Update: see the latest version of this code here.
The new navigation architecture in Silverlight 3 is very exciting as it substantially improves the viability of Silverlight for use replacing html websites (except for the lack of a hyperlink class, which I can't understand not being included in Silverlight 2). I'm currently developing a website which will be running Silverlight 3 and have discovered some interesting issues with the URI mapping architecture as it currently stands in the beta.
The first thing I wanted to do with the URI mapping architecture was to add my own routing system where I could examine the URI and decide which page to send it to. Out of the box the Silverlight has a Uri Mapper class that allows you to use regular expressions to convert the display URI into the URI you wish to use. For example (in App.xaml):
<Navigation1:UriMapper x:Name="_uriMapper"> <Navigation1:UriMapping Uri="About" MappedUri="/Views/About.xaml"/> <Navigation1:UriMapping Uri="About/{person}/" MappedUri="/Views/About.xaml?person={person}"/> </Navigation1:UriMapper>
Unfortunately with the way that the URI mapping is structured at the moment, the only way to do this in code, rather than in xaml is to completely duplicate the UriMapper class and create your own specialized type of mapping. Ideally, there should be a UriMappingBase class and UriMapping should be derived from that. The classes that I have developed for this are shown below:
[ContentProperty("UriMappings")] public class CustomUriMapper : UriMapperBase { // Methods public CustomUriMapper() { UriMappings = new Collection<UriMapping>(); CustomUriMappings = new Collection<CustomUriMapping>(); } public override Uri MapUri(Uri uri) { Collection<UriMapping> uriMappings = UriMappings; if (uriMappings == null) { throw new InvalidOperationException("MustNotHaveANullUriMappingCollection"); } foreach (UriMapping mapping in uriMappings) { Uri uri2 = mapping.MapUri(uri); if (uri2 != null) { return uri2; } } foreach (CustomUriMapping mapping in CustomUriMappings) { Uri uri2; if (mapping.MapUri(uri, out uri2)) { return uri2; } } // now nothing... return uri; } // Properties public Collection<UriMapping> UriMappings { get; private set; } public Collection<CustomUriMapping> CustomUriMappings { get; private set; } } public abstract class CustomUriMapping { public abstract bool MapUri(Uri unMappedUri, out Uri mappedUri); }
This allows me to create my own custom routes so that if I need to do some custom analysis of the URI before I decide which page to use, this can be done, as shown below:
internal class CategoryRoute : CustomUriMapping { public override bool MapUri(Uri uri, out Uri mappedUri) { // check for a category CachedCategory category = ClientStaticCache.GetCategoryByPath(uri.ToString()); mappedUri = category != null ? new Uri(string.Format("/Pages/CategoryPage.xaml?categoryid={0}", category.CategoryId), UriKind.RelativeOrAbsolute) : null; return mappedUri != null ? true : false; } }
MapUri returns a bool because there are situations where you want to return a null URI. Why would you want to do this you ask, because in some scenarios you may wish to use a URI to display a dialog, for example, an about dialog. In this case you might have a mapping that looks like this:
internal class AboutBoxRoute: CustomUriMapping { public override bool MapUri(Uri unMappedUri, out Uri mappedUri) { mappedUri = null; if (unMappedUri.ToString()=="About") { AboutDialog dialog = new AboutDialog(); dialog.Show(); return true; // we are not going to go anywhere, just let the dialog display } mappedUri = null; return false; } }
If the unmapped URI was equal to “About”, the about dialog would display and null would be returned from the UriMapper, so no navigation would occur . Unfortunately there is a bug in the Silverlight beta, which means that returning null from the UriMapper can in some scenarios cause an exception. I’ve filed a bug on connect for this and hopefully it will be fixed before RTW.
Adding the custom URI mapper to your project is the same as adding the Microsoft one, except that you reference a different class.
<routing:CustomUriMapper x:Key="uriMapper"> <Navigation:UriMapping Uri="search/{searchfor}" MappedUri="/pages/searchpage.xaml?searchfor={searchfor}"/> <routing:CustomUriMapper.CustomUriMappings> <routing:AboutBoxRoute/> <routing:CategoryRoute/> </<routing:CustomUriMapper.CustomUriMappings> </routing:CustomUriMapper>
As you can see, you can add any custom routes directly in the xaml.
So there are some solutions for some issues with the URI mapping as currently implemented in Silverlight 3. In my next post I will explain some of the issues that I haven't been able to work around.
Original Post: Custom routing using the Uri Mapper in Silverlight 3
The content of the postings is owned by the respective author. Silverlight Feeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on Silverlight Feeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.