nRoute: At last a Quick Start

Posted by Rishi on 06-Apr-09 4:09 PM - Comments (4)

Tags: , , | Categories: .NET, Code, nRoute

In post-after-post I've been digging deeper and deeper into the innards of nRoute, whilst neglecting a gentler way in - to correct that this post will provide a simple quick start. We'll create a sort of master page, and a couple of child pages to navigate. So let's get on..

Step 1.
We start with an empty Silverlight application, named what ever you prefer. It will probably ask you about hosting options, you can choose either but an automatically generated test page should suffice.NewProject

Step 2.
We need to add reference to nRoute's assembly, a downloadable version of the assembly is available at Codeplex or you can compile your own version if you have the source code.

Step 3.
Once we have referenced the assembly, on the main page (Page.xaml, which will act as our master page or shell if you like), we will import two namespaces from the nRoute.Silverlight assembly. The nRoute.Controls namespace provides us with a navigation container and the nRoute.Behaviours.Navigation provides us with attachable behaviours. An abbreviated version of the page.xaml is show below, note I also remove the Width and Height attributes.

<UserControl 
	...
    xmlns:cntr="clr-namespace:nRoute.Controls;assembly=nRoute.Silverlight"
    xmlns:nav="clr-namespace:nRoute.Behaviours.Navigation;assembly=nRoute.Silverlight">
    
    <Grid x:Name="LayoutRoot" Background="White">
    </Grid>

</UserControl>

Step 4.
Up next, we will create the main page's layout. I prefer the grid control to structure the layout, so in this case will take the existing Layout grid and add two rows to it, with the first one being locked at 50(px), and other filling up the rest of the space. We will also add two controls to the grid, one a horizontal oriented stack panel for the first row, and a navigation container for the second row named "DefaultContainer". The xaml for the grid is show below:

<Grid x:Name="LayoutRoot" Background="White">

    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    
    <!-- NAVIGATION LINKS -->
    <StackPanel Grid.Row="0" Orientation="Horizontal"></StackPanel>
    
    <!-- MAIN CONTAINER -->
    <cntr:NavigationContainer Grid.Row="1" x:Name="DefaultContainer" />

</Grid>

Step 5.
Next we will add a couple of hyperlinks in the stack panel, this will represents a sort of flat menu which links to the various pages in the app. The hyperlink control will be appended with navigation related behaviours, one that identifies the Url to navigate to and another specifies which container should the navigation occur in, and the only answer available is the "DefaultContainer" element.  Also, we will have three pages namely Home Page (available at Url "Pages/Home/") , About Us (available at Url "Pages/AboutUs") and Contact Us (available at Url "Pages/ContactUs").  The xaml below shows the stack panel, note the margin and alignment.

<!-- NAVIGATION LINKS -->
<StackPanel Grid.Row="0" Orientation="Horizontal" 
    VerticalAlignment="Center" HorizontalAlignment="Center">

    <HyperlinkButton Content="Home Page" Margin="10"
         nav:Click.NavigateUrl="Pages/HomePage/" 
         nav:Click.NavigateHandlerElementName="DefaultContainer"/>
    
    <HyperlinkButton Content="About Us" Margin="10"
         nav:Click.NavigateUrl="Pages/AboutUs/"
         nav:Click.NavigateHandlerElementName="DefaultContainer" />

    <HyperlinkButton Content="Contact Us" Margin="10"
         nav:Click.NavigateUrl="Pages/ContactUs/"
         nav:Click.NavigateHandlerElementName="DefaultContainer" />

</StackPanel>

Step 6.
Now that we have a navigation structure, we will create three user controls to represent the links enlisted. And I suggest we add a folder in Visual Studio named "Views", where we will add three user-controls appropriately named "HomePage.xaml", "AboutUs.xaml" and "ContactUs.xaml". Note, the folder and user-control names are not particularly important, since we abstract them as Urls (really a boon for refactoring). Now, in the code-behind files for all the three controls we will add an attribute on each of the classes, identifying them as an content addressable by the given Url, along with a title for the page. The MapNavigationContent Attribute is available in the nRoute.Navigation namespace.
Mapping
Step 7. 
As for the content pages we need to fill it with some visuals - obviously so that it is discernable. I suggest let's add a Textblock in each saying I am so and so page with a different background colour to jar the senses. Secondly, we need to get rid of the default Width and Height Attributes as it will inherit the size from the container. Below is what my abbreviated xaml looks like for each of user controls.

<!-- Home Page User Control -->
<UserControl x:Class="SimpleQuickStart.Views.HomePage" ... >
    <Grid x:Name="LayoutRoot" Background="LightBlue">
        <TextBlock Text="I am the home page." />
    </Grid>
</UserControl>

<!-- About Us User Control -->
<UserControl x:Class="SimpleQuickStart.Views.AboutUs"... >
    <Grid x:Name="LayoutRoot" Background="GreenYellow">
        <TextBlock Text="I am the about us page."/>
    </Grid>
</UserControl>

<!-- Contact Us User Control -->
<UserControl x:Class="SimpleQuickStart.Views.ContactUs" ... >
    <Grid x:Name="LayoutRoot" Background="LightCoral">
        <TextBlock Text="I am the contact us page."/>
    </Grid>
</UserControl>

Step 8.
Lastly, we need to do two more things , one on the main page where we have the navigation container we need to tell it which page to show initially by setting it's "InitialUrl" property to the home page Url ("Pages/HomePage/") or which every Url you prefer. Secondly, in the application's code-behind file (App.xaml.cs) we need to call into the Navigation Service to automatically register all Urls mapped via attributes. This is a single call you place in the startup event-handler for the application, as show below.

<!-- In the main page, we set the InitialUrl property -->
<cntr:NavigationContainer Grid.Row="1" x:Name="DefaultContainer"
	InitialUrl="Pages/HomePage"/>

// In the application start up event, we call for automatically mapping 
// of all attributes defined navigation urls
private void Application_Startup(object sender, StartupEventArgs e)
{
    this.RootVisual = new Page();
    nRoute.Navigation.NavigationService.MapLoadedAssembliesRoutes();
}

And that's it we are done, we should now have an ugly-ass app for all our hard-work. Let me just recap the steps, you create a navigation container, then append your content with the relevant attribute, importantly call for auto-mapping to occur, set the initial Url to show, and setup the links/behaviours to functionalize the app. To simplify some of these steps, and a better design-time experience expect a set of Visual Studio templates.

In the follow-up post I'll take on simplifying this code, introducing application-level containers, showing alternative ways of mapping, highlight both deep-linking and browser shell-integration and hopefully stylise the look and feel. So do stay tuned, below you'll find the sample app running and the code for this quickstart.

Get Microsoft Silverlight

Quickstart Code (88 KB, includes nRoute.Silverlight.dll)

Comments

trackback
DotNetKicks.com
on 19-Mar-09 7:06 AM
Trackback from DotNetKicks.com

nRoute: At last a Quick Start

trackback
DotNetShoutout
on 19-Mar-09 7:08 AM
Trackback from DotNetShoutout

nRoute: At last a Quick Start

dines
dines
on 22-Mar-09 8:19 AM
Hi,

I have played around with asp.net mvc as well as with silverlight 2. After working with asp.net mvc I thought, wouldn't it be cool to have a infrastructure like this for silverlight... and then I saw your project! Great work...!
While playing with it, I found out one thing, which behaves not as I have expected it. I don't know if this is by design or you would not like to have people doing this =). Maybe I am just missing something here.
I have nested containers. And I put a hyperlink into a nested page which navigates to a top-level page. Pages/Home/Nest/SubPage1 and on clicking the hyperlink it should navigate to Pages/About..
I have a container in my Page.xaml (Name=PageZone) which holds "home" and "about" and I have one in Nest.xaml (Name=NestZone) which holds "subpage1" and "subpage2". So when I click within a supage on a link and want to navigate to "about" and make it land in "PageZone" it navigates to "About" but puts it into NestZone...
Did you also experienced something like this?

cheers
D.

Rishi
Rishi
on 28-Mar-09 8:01 PM
Hi Dines, let me just first describe how the navigation behaviour by default.. when you ask it to navigate (I am presuming using navigation's attached behaviours) it needs find a handler of type INavigationHandler.. Now, the logic behind finding the handler is as follows:

1. If you have defined the INavigationHandler, using the NavigationHandler property it will use that
2. Else if, you have specified an Navigation Container Element, using the NavigationHandlerElementName property it will use that
3. Else if, it will look in the Visual Tree for any parent that implements the INavigationHandler, and if it finds one it will use that
4. Else, it will check if we have an application-wide container specified, it will use that
5. All else, it will throw an exception saying it can't handle your request because it couldn't find a handler

If I am reading your question right, it is working as expected.. now, if you want it to work differently, specify either the INavigationHandler (by binding) or equally the navigation container element (by name) that should specifically handle your request.. so something like this will help..

<HyperlinkButton ...  
         nav:Click.NavigateUrl="YourUrl"    
         nav:Click.NavigateHandlerElementName="ContainerName"/>

Hope this helps..

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading