Wednesday 7 October 2009

Silverlight 3 Navigation – navigating from a UserControl

This post has moved to http://www.scottleckie.com/2009/10/silverlight-3-navigation-%e2%80%93-navigating-from-a-usercontrol/

I’ve been toying with Silverlight over the last couple of weeks and, I have to say, it’s much more complete than ASP.Net ever was (**). Lots of new paradigms to get my head around, of course, but overall it’s a very complete solution for an RIA.
Anyway, to the point of this posting; the new (in Silverlight 3.0) Navigation Framework is great; it allows you to present a common interface and have new pages display in a know part of the browser window, supports browser back/forward, and URL rewrites. See here for more information.
If you are inside a page that is controlled by the framework, then you are able to call on the NavigationService.Navigate method to divert control to a new XAML page. For example;
this.NavigationService.Navigate( new Uri( String.Format( "/Views/Item.xaml?title={0}&type={1}", ...), UriKind.Relative ) );


This is all well and good if you inherited from the Page class within the Navigation Framework, but what if you are a user control, out on a limb, with no knowledge of the Navigation Framework? In my case, I have a user control that displays a treeview context list to the user. Some of the options are static (“select all machines”, “select all software”, etc) and some is dynamic (“select a machine of type…”). Once the user clicked on their desired option, we did some menu calculations and then finally asked the Silverlight Navigation Framework to display the required page in the Content frame. Except we couldn’t… a UserControl has no knowledge of the Navigation Framework and so can’t instruct it to navigate to a specific page.


Darn.


The ultimate solution is that the application’s “main page” (which we can find down the Application.Current map) is able to influence the navigation, so stage one was to add a “public bool NavigateTo(Uri uri)” method to the MainPage.xaml file;


public partial class MainPage : UserControl
{
public bool NavigateTo(Uri uri)
{
return this.ContentFrame.Navigate(uri);
}





Now, we just need to call the NavigateTo method from our non-navigational UserControl. To do this, we need to find the Main Page, which we do by tracking back to the “RootVisual” element in the MainPage.xaml file (if you renamed any of this, then you’ll need to change some of the references, below);


private void RunMenu(string requestedMenu, object o)
{
MainPage mp = ((MainPage) Application.Current.RootVisual as MainPage);
switch (requestedMenu.ToLower())
{
case "machines": mp.NavigateTo(new Uri("/MachineList", UriKind.Relative)); break;
case "software": mp.NavigateTo(new Uri("/Home", UriKind.Relative)); break;


Here, we find a reference to the Main Page via Application.Current.RootVisual (remember MainPage.xaml?) Once we’ve done that, we call the main page object and ask it to “NavigateTo” a new page.


To put this into context, here’s the application browser view;


image





(** only in terms of the fact that ASP.Net always seemed to be a halfway house to me – you needed to jump through a lot of hoops to persuade the browser to do what you want it to do. Silverlight, of course, was designed as an RIA from conception so it seems to fit more easily than a native HTML / ASP.Net app. Of course, the trade-off is that you need to present a whole new runtime environment to the user, in terms of the Silverlight VM, but I can live with that for a) more rapid development and b) less concern over what the browser is going to do with our code.)

No comments:

Post a Comment