The other day, I mentioned how we developers are artists in every right - well, below is artistry of another kind, one you just have to tip you hat to..

This was done on the streets of Buenos Aires and Baden by an amazingly talented artist named Blu. In the video above, titled Muto, each frame was drawn and photographed sequentially with with some added animation. For me the character-art is mind-blowing, the scale staggering, but what impresses the most is the patience and vision exuded by its creator.

On a related note, here is a little food-for-though I picked up from Robby Ingebretsen's blog post:

[Design] involves creativity in the way doing a crossword puzzle involves creativity. You need some imagination and knowledge. I think of artists as creative because they have to invent something out of nothing. I think designers design because they can't invent something out of nothing.

Posted by Rishi on 18-Apr-09 11:23 AM, 20 Comments

Tags: , ,
Categories: Art, Other

I've yet to cover all the features of nRoute in depth, but since a lot of people are downloading the framework and the demo app, I thought let me step through code in the demo app to at least provide a rounded overview of the features in nRoute. To structure the content, I will headline each significant part and highlight the relevant aspects in the code. Further, to make some distinctions clear, this post is divided into two parts, one relates to the Infrastructure in the demo app and the other relates to how the consumable/actionable content integrates with the infrastructure, using nRoute of course. Moreover, to get the most out of this long-long post please familiarize yourself with the basics of nRoute, using my series of earlier posts.


PART I: INFRASTRUCTURE SETUP

The Application Class

Right off the bat, in the app.xaml.cs we can see that the application class inherits from a custom type defined in nRoute called StatefullApplication. I've mentioned this before, but the idea of deriving off a custom application type is to primarily give home to a default container. The default container is an application-wide navigation container hook-up point, wherein any navigation without a specified container is handled - think unhandled exception handling as a mental model.

public partial class App 
	: nRoute.Navigation.Application.StatefullApplication { .. }
Now we have several types of navigation containers build into nRoute, and equally you can define you own custom ones. In this instance we are using a "Statefull Navigation Container" and its companion application class derivate (the StatefullApplication type) - I had earlier defined the Statefull Container as follows:

This one basically stores the state of the page when you leave it, and restores it when you navigate onto it. This doesn't have a stack of back or forward pages history, it keeps one list of states and applies it whenever you navigate onto the page. So simply your last state is restored once you navigate to the page, in either back/forward or direct navigation manner.

The StatefullApplication type provides a number of features, one that is pertinent here is the NavigationContainer property which allows us to set any navigation container as the application's default container - and as you will read ahead that is exactly what we do.

The Workspaces/Blades Model

Before we can dig deeper into the application class, I want to explain one of the core aspect of the UI - which is the blades/workspaces model that provides one or more tab-like containers for the application. Each workspace/blade is basically a StatefullContainer which can collapse or expand into full view, and features a title bar to its left (see Workspace.xaml). I've exposed all the interaction functionality of the workspace through an interface called IWorkspace, nothing special really - basically think of it as a specialized tab. Further, in order to show the blades/workspaces I created a custom panel called WorkspacesStackPanel - essentially it is like a horizontal accordion, specialized to only show one active workspace and vertical title-bars for all the other collapsed workspaces.

Workspace/Blades UI

To manage the workspaces there is the WorkspacesViewModel type, which should have really been called the WorkspacesController type. And like my suggestion, this is basically a simple application-wide controller for managing all the workspaces. Again nothing special, however for your own use you might want to amend this to allow adding/removing workspaces, with perhaps a more streamlined workspace-interaction pattern. This controller is exposed on the Application class using the read-only WorkspacesViewModel property.  

The Application Startup

The fun starts in the startup event of the application, we do a couple of things here:

  • We set the root visual to the MasterPage.xaml [Line 3]
  • We then create the workspaces, which initializes the mentioned WorkpsacesViewModel type [Line 5]. Note you can create your own strategy to customize the number of workspaces, in the demo app's case we try and read the "workspaces"  querystring key for values between 1 and 9 (try appending "?workspaces=7" to the Url, before the bookmark)
  • We set the DataContext of the root visual to the WorkpsacesViewModel, this cascading'ly hooks up the visuals [Line 6]
  • Next, we register for browser integration, this functionality is availed through the inherited base application class. Note, while registering we also specify the default Url, which in this case we read from the browser's current bookmark or use the specified default value ("Home/")  [Line 8]
  • Next, like before we set the active workspace's Initial Url by reading the browser's Bookmark or use the Default value ("Home/") [Line 9] - this allows for the deep-linking feature
  • And also we set up a handler that updates the Browser's Title when the active workspace changes [Line 11]
private void Application_Startup(object sender, StartupEventArgs e)
{
    this.RootVisual = new MasterPage();

    CreateWorkspaces(3); // delegates to a helper function
    ((FrameworkElement)this.RootVisual).DataContext = _viewModel;

    base.RegisterBrowserNavigationHooks(base.GetCurrentBookmarkOrDefaultUrl("Home/"));
    _viewModel.ActiveWorkspace.InitialUrl = BrowserIndexedNavigationBridge.RemoveBookmarkIndexerInfo(GetCurrentBookmarkOrDefaultUrl("Home/"));

    _viewModel.ActiveWorkspaceChanged += (s, e2) =>
        base.SetBrowserWindowTitle(this.NavigationContainer != null ? this.NavigationContainer.Title : null);
}

Browser Integration

One of the side-effect of the multiple blades/workspaces is that it complicates the browser-integration strategy, because the browser only keeps a single history-stack whereby we need multiple of these on a per workspace/blade basis. Not to worry though, because like everything else in nRoute the browser integration strategy is totally configurable. The solution in this case is that we append the bookmark with an indexer that identifies which workspace the bookmark belongs too (it looks like ¶3 or ¶1 postfix). The integration is achieved by overriding the CreateBrowserNavigationBridge method in the application class, and providing a custom implementation of type WorkspaceBrowserBridge. When the "bridge" adds to the browser history our custom implementation appends the bookmark with the active workspace index, and when the browser navigates back or forward it parses the workspace index and accordingly sets the active workspace and the Url. This allows us to have a single history-stack for multiple workspaces/bridges integrated within the browser, with full deep-linking support. As a notable, the browser integration behaviour is based on a simple interface of type IBrowserNavigationBridge.

Master Page

The master page (or shell if you prefer) is actually simpler than it appears, it is basically a three column by two row grid (as shown by the red lines), and three borders fill the grid area to define the rounded shape of the visual (as shown by the green borders). We also dynamically clip the grid as per the edges of the borders. The Icons on the left, are placed in a canvas and aligned to the bottom. The bar at the bottom is also a grid, and on the right we have stack panel that block-by-block fills in the side bar. 
 Master Page Visual Breakdown
The main content is an ItemsControl element which is data bound to the workspaces list, and uses the aforementioned WorkspacesStackPanel as the ItemsPanelTemplate.

<!-- WORKSPACEs -->
<ItemsControl ItemsSource="{Binding Workspaces}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <cnt:WorkspacesStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl> 
Visual Effects

Or the lack off, should be title as I absolutely took a minimalistic approach in recreating the reference UI. Since I made the app in SL2, I purposely deferred using visual goodies in favour of the goodness on offer in SL3 - particularly the GPU based shader effects and Perspective 3D. The one thing I did attempt was the hover-effect as without the visual-highlighting the navigation-links wouldn't be self-apparent. The hover-effect uses attached behaviours with an extensible model so that you can extend it to your custom controls, still it is quite comprehensive. The use template is also pretty simple, have a look:

<Border Style="{StaticResource SideButtonBorderColourBrush}" 
    hvr:Hover.HoverBackground="{StaticResource SideButtonHightlightBkgBrush}">
In the snippet above, we attach the behaviour to a border and say on hover (mouse over event) change the background to the brush identified. Depending on the visual element you can change the background, foreground and the border on hover. Note, you can adopt this behaviour for use elsewhere, but consider using storyboards to give transitions a visually engaging lift.


PART II: CONSUMABLE & ACTIONABLE CONTENT
 

Content Composition

To this point we have had the application's infrastructure basically all spelt out, without even having to delve into the actual content - which is good because we want minimal intermingling of the content and the infrastructure that surrounds it. In fact this is the forte of nRoute, that we can keep the content and containers loosely coupled from each other using only Urls - and nRoute takes care of the composition for you. Read about the basics of navigation-based  composition in my previous post.

Content Mapping

Now, for the composition to occur we need to mark the content using Urls as their identifier, and to that end we have a couple of way build-in into nRoute - though yet again, you have a flexible pass in that you can create your own loading/mapping strategy. My preference is normally to use attribute-based mapping system in nRoute owing to its simplicity (and which again like everything else you can customize/extend). Below, are some relevant snippets from the code-behinds of various content files, using attribute based mapping:

// Mapping in HomePage.xaml.cs
[MapNavigationContent("Home/", "Home Page")]
public partial class HomePage : UserControl { .. }

// Mapping in InformationPage.xaml.cs 
[MapNavigationContent("Pages/AboutInformation", "About")]
public partial class InformationPage : UserControl { .. }

// Mapping in FuturePageViewModel.cs
[MapViewModelViewNavigation("Pages/FuturePage/{Name}", 
	typeof(FuturePageViewModel), typeof(FuturePage))]
public class FuturePageViewModel { .. }
Using the MapNavigationContent attribute is one the simplest way to annotate content as Urls; as shown above we put it on the content type (in this case the HomePage class), and specify it's Url Identifier ("Home/") and optionally a static title ("Home Page") associated with that Url. The other attribute shown is MapViewModelViewNavigation which as evident is helpful when using the M-V-VM pattern, and therein we can associate the Url with the View type (in this case the FuturePage type) and its associated View-Model type (FuturePageViewModel type). Further, using this attribute the View-Model type is automagically injected into the View, by setting it as it's DataContext when the Url is requested for. Do note, you have flexibility as to where you put these attributes, see my other posts for examples.

The other build-in way to register is akin to what is present in ASP.NET 3.5sp1 or MVC, which is via statically registering against the NavigationService static class. Below, is an abbreviated snipper from the application class in the demo app:

protected override void RegisterNavigationsRoutes()
{
    NavigationService.MapLoadedAssembliesRoutes();
	NavigationService.MapRoute("Images/HeartYourWeb",
        new NavigationResourceHandler("Images/HeartYourWeb.xaml", NavigationResourceHandler.XamlLoader));
	...
}
Here the first call is actually to enable attribute based mapping (for all loaded assemblies), and there after we specifically map the route for a loose-xaml file using the Url Identifier "Images/HeartYourWeb". And as this is a resource in the assembly we use the NavigationResourceHandler to help with that. For more information on mapping navigation routes please see my other blog posts, however the big-picture take-away should be that mappings serve the function of abstraction, in this case abstraction of resources as Urls.

Content Navigation

Given the mappings, we can use the registered Urls to navigate to the content; and for most purposes I recommend using the extensive-set of behaviours in nRoute to avail navigation. Throughout the MasterPage you will see exclusive use of the navigation behaviours for content navigation, show below are some examples:

<!-- NAVIGATE ON MOUSE DOWN ON TEXTBLOCK -->
<TextBlock .. nav:MouseDown.NavigateUrl="Pages/FuturePage/Folders" />

<!-- NAVIGATE ON Ctrl+H KEY DOWN, note this is part of a Behaviours Collection -->
<bhv:KeyUpNavigate NavigateUrl="Home/" Key="H" KeyModifiers="Control" />
In the first case here, we attach the navigate behaviour to a TextBlock which on the (LeftButton)MouseDown event will navigate to the specified Url. And in the second case, we have attached another behaviour on the UserControl, that on recognizing the Cntrl+H key combo will navigate to the "Home/" Url. As you can see for the most part this is all pre-defined, however it doesn't have to be, you can also use the Url Address bar at the bottom of the MasterPage to manually navigate to any valid Url (try about:blank). I hope you can see how we at first abstracted the content via Urls, and using the same Urls also realized them visually.

State Management

In order to use the state management facilities in nRoute, one has to opt in using a simple interface called ISupportNavigationState - which is the case with the FuturePageViewModel type. As mentioned earlier this is the View-Model class backing the FuturePage.xaml, and the logic is trivially simple - all it does is provide a random brush (see OnChangeColour which is exposed by the ChangeColourCommand) from the application resources, and also saves/restores both the selected brush and any text entered by the user. It also makes use of tokenized Urls, as specified in the MapViewModelViewNavigation attribute, have a look:

[MapViewModelViewNavigation("Pages/FuturePage/{Name}", 
	typeof(FuturePageViewModel), typeof(FuturePage))]
public class FuturePageViewModel 
	: ISupportNavigationState, INotifyPropertyChanged { .. }
In the Url registered we have the {Name} token, which gives us the UI's title to display; this token-value pair is availed in the InitializeState method via its "state" parameter (a name-value dictionary). So a Url like "Pages/FuturePage/LightUpTheWeb/" will display "Light Up The Web" as its title in the page, try here. This is rather vain, but you could easily get in your OrderId or CustomerId via the Url and do something more constructive.

The second key construct here is the SaveState method that basically takes the two key properties (the selected colour and entered text) and returns it in a dictionary - which represents the state of the page. Now when you navigate onto the page (via either Back/Forward/New navigation manner) the StatefullContainer will restore the state by passing back the dictionary you saved earlier (as seen in the RestoreState method), and in this case we just use that to restore the two key properties. It is really very straightforward, and the benefit being that the visuals (and the View-Model in this case) don't need to be persisted in the memory, only the relevant state is stored and restored as required by the container.

Action De-Composition

In addition to the content composition and navigation, nRoute also features a set of functionality that allows you to address actionable code via Url identifiers; please refer to my actions related post for detailed information. In the Demo app, you will find trivial examples of how to use the Action infrastructure, the snippet below (from WorkspaceNextPreviousActions.cs) shows an action handler that allows you to select the next or previous workspaces/blade:

[MapActionHandler("Workspace/Actions/Previous")]
[MapActionHandler("Workspace/Actions/Next")]
public class WorkspaceNextPreviousActions : IActionHandler 
{
    public bool CanHandle(IActionDefination action)
    {
        return true;
    }

    public void Handle(IActionDefination action)
    {        
        var _viewModel = ((App)Application.Current).WorkspacesViewModel;
        var _newIndex = 0;

        .. // implementation details

        // we select a new workspace, note the use of the dispatcher
        action.Request.Dispatcher.BeginInvoke(() => _viewModel.ActivateWorkspace(_newIndex));
    }
}
The idea behind actions is to decompose your application's reusable code into a set of independent handlers, which are addressable in a loosely coupled fashion using Url. In the case above we mark the IActionHandler implementation with two Url Identifiers (see the MapActionHandler Attributes) that either select the previous workspace or the next workspace as per the requested Url. Also observe that Actions are consumed off the UI thread, hence the use of the dispatcher [Line 18]. What makes the investment of creating IActionHandler worthwhile is the structured but loosely-coupled way of consuming the exposed functionality, as show below:
<!-- NEXT PREVIOUS ARROWS -->
<TextBlock ToolTipService.ToolTip="Select Previous Workspace" ... 
           acn:MouseUp.ActionUrl="Workspace/Actions/Previous"  />
<TextBlock ToolTipService.ToolTip="Select Next Workspace" ... 
           acn:MouseUp.ActionUrl="Workspace/Actions/Next" />
As you can see here, we have basically attached behaviours to the TextBlocks which on (LeftButton)MouseDown event execute the action identified by the Url (without any direct reference to the handler). Another point to note if you try and execute an Action Url that isn't registered, it will raise an exception - this is design, because Actions per se have no visual component and without any indicator to their existence, calls might go unheeded which is an unacceptable outcome. So Urls in nRoute might be very loosely-coupled locators, but they are also structured and unambiguous as content/action providers (i.e. not magic-strings).


PART III: SUMMARY

Even though the demo app lacks substantial content, it demonstrates a range of features available in nRoute - however, beyond the technical ins-and-outs I hope what is also apparent is what nRoute brings to the table. From my perspective, nRoute sits in-between the infrastructure code and the actual consumable/actionable content, it bridges the chasm between the two - which in turn makes your code more adaptable and equally your infrastructure more changeable, largely independent of each other.

EDIT: added the State Management section

Posted by Rishi on 16-Apr-09 1:46 PM, 23 Comments

Categories: nRoute

Over the last couple of weeks I've got a lot of positive feedback on nRoute, which is absolutely delightful and I am very thankful to everyone for that. I am sure every developer (an artist in every right) is thrilled when their work is appreciated, and I am no different - plus all this definitely pushes us to do even better work.

Over the weekend nRoute and it's Future Desktop demo app was featured on both Channel 9, and on10. They were also highlighted on a Spanish technology site under the title "2019 comienza en 2009", which translated means "2019 begins in 2009", interesting way to put it. Plus they were also numerous other mentions on blogs from all over the world, all very exciting.

Get Microsoft Silverlight Godzilla

Lastly, I want to kind of put out a teaser that something is coming to nRoute that would be r/evolutionary. I personally think it is going to be Godzilla huge, and take the web in a new direction. These are very bold statements for sure, and I'm even prone to hyperbole - still there is something I am definitely very very excited about, and you might want to keep an eye out for it too!

Posted by Rishi on 14-Apr-09 12:36 AM, 17 Comments

Categories: nRoute, Personal

I just read an article by Micheal Sync about implementing property changed notifications with Expression Tree, I liked what I saw but didn't appreciate the inheritance requirement (as always). So I quickly whipped up three alternate way using extension methods, have a look:

using System;
using System.ComponentModel;
using System.Linq.Expressions;

namespace Orkpad.Samples
{
    public static class NotifyPropertyChangedExtensions
    {

        public static void NotifyPropertyChanged<TValue>(this Object target, 
            Expression<Func<TValue>> propertySelector, Action<string> notifier)
        {
            if (notifier != null)
            {
                var memberExpression = propertySelector.Body as MemberExpression;
                if (memberExpression != null)
                {
                    notifier(memberExpression.Member.Name);
                }
            }

        }

        public static void Notify<TValue>(this Action<string> notifier, 
            Expression<Func<TValue>> propertySelector)
        {

            if (notifier != null)
            {
                var memberExpression = propertySelector.Body as MemberExpression;
                if (memberExpression != null)
                {
                    notifier(memberExpression.Member.Name);
                }
            }

        }

        public static void Raise<TValue>(this PropertyChangedEventHandler handler, Expression<Func<TValue>> propertySelector)
        {

            if (handler != null)
            {
                var memberExpression = propertySelector.Body as MemberExpression;
                if (memberExpression != null)
                {
                    var _sender = ((ConstantExpression)memberExpression.Expression).Value;
                    handler(_sender, new PropertyChangedEventArgs(memberExpression.Member.Name));
                }
            }

        }

    }

    // I've tested this in Silverlight it works fine, should work in WPF too.
    public class NameValuePair : INotifyPropertyChanged
    {

        string _name;
        string _value;

        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                this.NotifyPropertyChanged(()=> this.Name, RaisePropertyChanged);
                // I don't like to new up, but this is also usable
                //new Action<string>(RaisePropertyChanged).Notify(() => this.Value);
            }
        }

        public string Value
        {
            get
            {
                return _value;
            }
            set
            {
                _value = value;
                PropertyChanged.Raise(() => this.Value);
            }
        }


#region INotifyPropertyChanged Members

        void RaisePropertyChanged(string name)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        public event PropertyChangedEventHandler PropertyChanged;

#endregion

    }
}

Of the three ways I've show, I like the last one using the PropertyChangedEventHandler best - it's quite compact and tidy. In fact, we can use similar extension-method "pattern" to call/raise handlers in various other scenarios. The other two ways are also useful if you don't have direct access to the event, like in cases of inheritance or where you have to go through a wrapper. Now, I can't speak to the performance of either solution - though, if someone can show figures on performance especially relative to the "normal way" that would be super!

// Recap

// Way 1
this.NotifyPropertyChanged(() => this.Name, RaisePropertyChanged);
// Way 2
new Action<string>(RaisePropertyChanged).Notify(() => this.Name);
// Way 3
PropertyChanged.Raise(() => this.Name);
 

Posted by Rishi on 12-Apr-09 8:49 AM, 18 Comments

Categories: Code, Code

One of the cool thing about the Silverlight 3 Navigation Framework (SL3NF) is that out-of-box it comes with an usable default template. But what is even cooler, is that Microsoft will provide a number of swappable themes for the default template. Now, I am no Microsoft and if you were to choose nRoute I wouldn't want you to miss out on all the fun, so in this post I'll show you how we can "borrow" some style. Alternatively, you can use this as a guide to consume these themes in any Silverlight 2 (SL2) projects even without nRoute.

What I will do is go over each file in the SL3NF template, and translate each SL3NF specific construct into its SL2/nRoute equivalent. I kick off with a blank SL2 Application, to which I add an nRoute assembly reference.

The Main Page

I start by renaming the default Page.xaml in the SL2 project into MainPage.xaml as per it's equivalent in SL3NF template. Next I copy over the xaml from the SLN3F template, and ignore the code behind. Now, I'll make a couple of changes to MainPage's copied xaml, as itemized below:

  • Introduce two nRoute related XML namespaces (nav for nRoute.Behaviours.Navigation and cntr for nRoute.Controls) also I remove the SL3 specific navigation namespaces
  • Next I remove all the Event Handling attributes (like Click="NavButton_Click") and also the Tag attributes (like Tag="/Views/HomePage.xaml")
  • I change the navigation:Frame into cntr:NavigationContainer and remove it's "Source" attribute
  • On each of the buttons I introduce a navigation behaviour, with something like nav:Click.NavigateUrl="Views/HomePage/"

Below, are the xamls for the MainPage.xaml file, first from SL3NF and then SL2 Project:

<UserControl x:Class="SilverlightApplication.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation">
    <Grid x:Name="LayoutRoot" Background="{StaticResource ApplicationBackgroundColorBrush}">

        <Grid Style="{StaticResource NavigationContainerStyle}">

            <Border Style="{StaticResource NavigationBorderStyle}">

                <StackPanel Style="{StaticResource NavigationPanelStyle}">

                    <Button Click="NavButton_Click" Tag="/Views/HomePage.xaml" Content="name list" 
                            Style="{StaticResource PageLinkStyle}"/>
                    <Button Click="NavButton_Click" Tag="/Views/AboutPage.xaml" Content="detail list" 
                            Style="{StaticResource PageLinkStyle}"/>

                </StackPanel>

            </Border>

            <Border Style="{StaticResource BrandingBorderStyle}">

                <StackPanel Style="{StaticResource BrandingPanelStyle}">

                    <TextBlock Text="your." Style="{StaticResource BrandingTextNormalStyle}"/>
                    <TextBlock Text="application." Style="{StaticResource BrandingTextHighlightStyle}"/>
                    <TextBlock Text="name" Style="{StaticResource BrandingTextNormalStyle}"/>

                </StackPanel>

            </Border>

        </Grid>

        <Border Style="{StaticResource FrameContainerStyle}">

            <Border Style="{StaticResource FrameInnerBorderStyle}">

                <navigation:Frame x:Name="Frame" Source="/Views/HomePage.xaml"
                                  HorizontalContentAlignment="Stretch"
                                  VerticalContentAlignment="Stretch"
                                  Padding="15,10,15,10"
                                  Background="White"/>

            </Border>

        </Border>

    </Grid>
</UserControl>
<UserControl x:Class="nRouteNavigationTemplate.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cntr="clr-namespace:nRoute.Controls;assembly=nRoute.Silverlight"  
    xmlns:nav="clr-namespace:nRoute.Behaviours.Navigation;assembly=nRoute.Silverlight">
    <Grid x:Name="LayoutRoot" Background="{StaticResource ApplicationBackgroundColorBrush}">
       
        <Grid Style="{StaticResource NavigationContainerStyle}">

            <Border Style="{StaticResource NavigationBorderStyle}">

                <StackPanel Style="{StaticResource NavigationPanelStyle}">

                    <Button nav:Click.NavigateUrl="Views/HomePage/" Content="home" 
                            Style="{StaticResource PageLinkStyle}"/>
                    <Button nav:Click.NavigateUrl="/Views/AboutPage/" Content="about" 
                            Style="{StaticResource PageLinkStyle}"/>

                </StackPanel>

            </Border>
            
            <Border Style="{StaticResource BrandingBorderStyle}">

                <StackPanel Style="{StaticResource BrandingPanelStyle}">

                    <TextBlock Text="your." Style="{StaticResource BrandingTextNormalStyle}"/>
                    <TextBlock Text="application." Style="{StaticResource BrandingTextHighlightStyle}"/>
                    <TextBlock Text="name" Style="{StaticResource BrandingTextNormalStyle}"/>

                </StackPanel>

            </Border>

        </Grid>

        <Border Style="{StaticResource FrameContainerStyle}">

            <Border Style="{StaticResource FrameInnerBorderStyle}">

                <cntr:NavigationContainer x:Name="Frame"
                                  HorizontalContentAlignment="Stretch"
                                  VerticalContentAlignment="Stretch"
                                  Padding="15,10,15,10"
                                  Background="White"/>

            </Border>

        </Border>

    </Grid>
</UserControl>
Next, have a look at the code-behinds, also first from the SL3NF followed by the SL2 project.
namespace SilverlightApplication
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void NavButton_Click(object sender, RoutedEventArgs e)
        {
            Button navigationButton = sender as Button;
            String goToPage = navigationButton.Tag.ToString();
            this.Frame.Navigate(new Uri(goToPage, UriKind.Relative));
        }

    }
}
namespace nRouteNavigationTemplate
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }
    }
}

Now, if you wanted to consume these designs in SL2 without nRoute, you can replace the NavigationContainer with a plain ContentContainer and put in your own mechanism to switch its content.

Home Page

In the SL3NF the home page is based on a newly introduced type called Page, well, for the SL2 project I go for plain old UserControl. And also we don't need the navigation namespace or the title property, but the main grid from the template is copied intact. The xaml of both projects are show below, the first one is from the SL3NF.

<navigation:Page x:Class="SilverlightApplication.HomePage" 
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           Title="HomePage Page">
    <Grid x:Name="LayoutRoot" Background="White">
        
        <StackPanel> 
            
            <TextBlock Text="Home" Style="{StaticResource HeaderTextStyle}"/>
            
            <StackPanel Style="{StaticResource ContentTextPanelStyle}">
            
                <TextBlock Text="To learn more about Silverlight visit " Style="{StaticResource ContentTextStyle}"/>
                <HyperlinkButton Content="http://www.silverlight.net" NavigateUri="http://www.silverlight.net" Style="{StaticResource HyperlinkButtonStyle}"/>
            
            </StackPanel>
        </StackPanel>
    </Grid>
</navigation:Page>
<UserControl x:Class="nRouteNavigationTemplate.Views.HomePage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid x:Name="LayoutRoot" Background="White">

        <StackPanel>

            <TextBlock Text="Home" Style="{StaticResource HeaderTextStyle}"/>

            <StackPanel Style="{StaticResource ContentTextPanelStyle}">

                <TextBlock Text="To learn more about Silverlight visit " Style="{StaticResource ContentTextStyle}"/>
                <HyperlinkButton Content="http://www.silverlight.net" NavigateUri="http://www.silverlight.net" Style="{StaticResource HyperlinkButtonStyle}"/>

            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>
Next are the code behinds, the first one is again from the SL3NF project.
namespace SilverlightApplication
{
    public partial class HomePage : Page
    {
        public HomePage()
        {
            InitializeComponent();
        }

        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

    }
}
namespace nRouteNavigationTemplate.Views
{
    public partial class HomePage : UserControl
    {
        public HomePage()
        {
            InitializeComponent();
        }
    }
}
About Page

The about page is almost exactly like home page - no need to show it all over again.

Error Page

The error page in the SL3NF is based on a new type called ChildWindow, which has no equivalent in SL2 so I'll skip importing this. However, nRoute does shows a modal error message, using the good-old MessageBox.

Application Class (App.xaml)

In the App.xaml file I basically copied all the content form the SL3NF, which was really the application.resources element. Now, the code-behind file in SL3NF is vanilla SL3 App class, though it notably uses a new ErrorWindow type to handle/show exceptions. However in the SL2 project we need to make a couple of change to the standard App class file, particulars enumerated below:

  • We inherit from a custom application class, of type NavigationApplication (Line 5)
  • We set attributes to the app class to map navigation content, specifically for the Home Page and the About Page. Note, we could have set the attributes on the UserControls themselves but this is another way, perhaps a neater way.  (Line 3 & 4)
  • We set the Application-Level Container to be the Main Page's Navigation Control (Line 19)
  • We set the Application-Level Container's Initial Url to load (Line 20)
  • And we register for Browser Integration Hooks specifically (Line 18)

The code behind files from both projects are show below, the first one like before belongs to the SL3NF.

namespace SilverlightApplication
{
    public partial class App : Application
    {

        public App()
        {
            this.Startup += this.Application_Startup;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            this.RootVisual = new MainPage();
        }

        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // If the app is running outside of the debugger then report the exception using
            // the browser's exception mechanism. On IE this will display it a yellow alert 
            // icon in the status bar and Firefox will display a script error.
            if (!System.Diagnostics.Debugger.IsAttached)
            {

                // NOTE: This will allow the application to continue running after an exception has been thrown
                // but not handled. 
                // For production applications this error handling should be replaced with something that will 
                // report the error to the website and stop the application.
                e.Handled = true;
                ChildWindow ErrorWin = new ErrorWindow(e.ExceptionObject);
                ErrorWin.Show();
            }
        }
    }
}
namespace nRouteNavigationTemplate
{
    [nRoute.Navigation.MapNavigationContent("Views/HomePage/", "HomePage Page", typeof(Views.HomePage))]
    [nRoute.Navigation.MapNavigationContent("Views/AboutPage/", "AboutPage Page", typeof(Views.AboutPage))]
    public partial class App : nRoute.Navigation.Application.NavigationApplication
    {

        public App()
        {
            this.Startup += this.Application_Startup;
            this.UnhandledException += this.Application_UnhandledException;
            InitializeComponent();
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            this.RootVisual = new MainPage();
            NavigationService.MapLoadedAssembliesRoutes();
            this.NavigationContainer = ((MainPage)this.RootVisual).Frame;
            ((MainPage)this.RootVisual).Frame.InitialUrl = this.GetCurrentBookmarkOrDefaultUrl("Views/HomePage/");
            this.RegisterBrowserNavigationHooks(this.GetCurrentBookmarkOrDefaultUrl("Views/HomePage/"));
        }

        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // If the app is running outside of the debugger then report the exception using
            // the browser's exception mechanism. On IE this will display it a yellow alert 
            // icon in the status bar and Firefox will display a script error.
            if (!System.Diagnostics.Debugger.IsAttached)
            {

                // NOTE: This will allow the application to continue running after an exception has been thrown
                // but not handled. 
                // For production applications this error handling should be replaced with something that will 
                // report the error to the website and stop the application.
                e.Handled = true;
                Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
            }
        }
        private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
        {
            try
            {
                string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
                errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");

                System.Windows.Browser.HtmlPage.Window.Eval(
                    "throw new Error(\"Unhandled Error in Silverlight 2 Application " + errorMsg + "\");");
            }
            catch (Exception)
            {
            }
        }
    }
}
The xaml files are basically the same, please see the attached samples.

Borrowing Styles

That's it, we are done - we have captured the same look and feel as the default template in SL3NF (see Sample 1 below). What's more, we can now get all the goodness of swappable themes, in fact I borrowed two themes Brad Adam posted on his blog as shown below (click to open).

Click to open Sample 1 
Sample 1: Download Code (12 KB)

Click to open Sample 2
Sample 2: Download Code (12 KB) 

Click to open Sample 3
Sample 3: Download Code (12 KB)

Would you like to see this as the default template for nRoute too, or one that highlights the full range of the features in nRoute?

Differences

I wanted to point out some differences between the two projects:

  • The nRoute version has absolutely zero code behind, that is not the case with SL3NF
  • nRoute has a relatively involved application code-behind file, but in defence the reason is that nRoute doesn't make a lot of assumptions that SL3NF implicitly makes for you. For example, we don't assume browser integration so you have to call for it explicitly, note you can provided your own implementation too. Similarly, we don't assume your content mapping/loading strategy because we give a number of options, which are further extensible, hence the need for explicit calling. And we also don't presume the presence of application-level containers, this has to be deliberately specified - but the advantage is that it gives you more flexibility - consider the demo app, each blade/workspace can provisionally take on the role of the default-container, which is a very useful and powerful concept
  • The nRoute version should work in SL2, SL3 and also on WPF
  • SL3NF has nicer error-handling facilities, build atop the newer components in SL3

Despite the apparent differences, going forward I will try and adopt the navigation related controls introduced in SL3. This is possible because nRoute was designed with extensibility in mind, and most of the new types can possibly be co-opted by slapping an interface or two on them. This will hopefully give you an even richer experience, and first-class toolset options.

Potential Problems

Let me point out two problems you might run into with nRoute, as it stands today:

  • The browser-integration script in nRoute has a problem with the standards-mode in IE, though it works fine in all other browsers. As a temporary fix for IE, you can remove the DOCTYPE statement in the host html/aspx file
  • By default or when you edit App.xaml file, VS will automatically make the App class inherit from System.Windows.Application type, which you'll need to remove if you have inherited from a custom application type. To do so, right-click and select "Go To Definition" on the "InitializeComponent' call in the App class's constructor method, where you can remove the offending inheritance call.

I hope this gives you have a bit of an idea about nRoute's standing vis-à-vis SL3NF. Going further, I will have a more direct one-to-one comparison between the two in an upcoming post.

Posted by Rishi on 07-Apr-09 3:20 PM, 22 Comments

Categories: 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)

Posted by Rishi on 06-Apr-09 4:09 PM, 25 Comments

Categories: Code, nRoute

My previous post detailed the Navigation Services infrastructure, in this post I will get into the Action Services Infrastructure. The Action Services also build above the Routing Services, however it has a markedly different API. The constant is that we use Urls as the primary identifier (optionally with name-value parameters), but the action themselves are executed in fire-and-forget manner. Like before I will take on each part individually, but first below is my mind-map type class diagram for Action Services.Click for full size shot Before we go ahead, let me point out that I've erroneously misspelt definition as "defination" as seen above - I will definitely correct that.  However, I'm quite prone to such mistakes, including all-things related to grammar, spellings, punctuation, syntax and the likes  - it's a known defect, so please do excuse me.

No Returns for a Two-Step Process

In the class diagram above you might have noticed, that we have an IUrlRequest derivate type called ActionRequest but no equivalent IUrlResponse derivative. That is because an Url based action doesn't return a value, think Action<T> delegate - even so there is nothing stopping you from relaying back a response albeit indirectly. Secondly, to get an action registered it is a two step process, one we register a route with an Url and then we register one or more handler against that route. The logic for this disconnection is that we can have zero or more handlers registered against the same route and, equally we can also unregister a handler - think Pub/Sub. The sample code below shows both the deeds:

// We need to register an action url
ActionService.MapAction("CounterAddRoute", "Counters/Add/{CounterName}");

// we can now register a handler
var _thumbsUpHandler = new ThumbsUpCounterHandler();
ActionService.RegisterHandlerByRoute("CounterAddRoute", _thumbsUpCounter);

// we register another counter
ActionService.RegisterHandlerByUrl("Counters/Add/{CounterName}", new ThumbsDownCounterHandler());

// and we can unregister a counter too
ActionService.UnRegisterHandlerByRoute("CounterAddRoute", _thumbsUpHandler);

In the snippet above, we first register an Url with a route name "CounterAddRoute", this helps us reference the route. We then create an instance of the "ThumbsUpCounterHandler" class that implements the IActionHandler interface, which we register as a handler for the route. The next statement shows how we can also register handlers against Urls just as we can against Routes - it is essentially the same thing either way. Also, as shown in the last statement we can also unregister handlers, note there is another way of doing this - which is by naming the handlers while registering so that you can unregister it by the handler name rather than the instance.

 IActionHandlerThe IActionHandler Interface

The IActionHandler interface is a contract that is used to respond to action requests. It's signature is very similar to the INavigationHandler and equally it is also very ICommands'que. Basically we check with the handler if can handle the action, if it can handle then only the handle method is invoked. The handle method also has a very simple signature, it get passed in an IActionDefination (or IActionDefinition) that contains the original request and the parsed parameters. Like everywhere else in the framework the parsed parameters are a merged name-value collection of the original request parameters, the default parameters set while defining the route, and the parsed token-parameters from the Url. And sequence for merging is such that request parameters override Url parsed parameters, which in turn override the default parameters.

One other critical thing to note is that when you register a handler you are registering an implicit singleton instance for handling all action requests, and so you have to be mindful of that in your handler's code. And if this doesn't suit you needs, just wrap it within a factory-style implementation of IActionHandler that can provision as required.

Action Request

Like I've mentioned earlier all requests constitute of two principle things, one the Url and two a name-value collection; as evident in the IUrlRequest interface below. The other member in that interface is the ServiceState property, which is supposed to be for internal use to carry service's own water.  ActionRequest Related Types 
The one thing the ActionRequest type adds is the Dispatcher property, which is self-descriptively a type of the Dispatcher class. This is important because the ActionHandlers are executed off the UI-thread and asynchronously, and to effect any results or changes this provides the bridge back to the UI thread.

Action Route Handler

The Action Service uses a specific IRouteHandler implementation of a type named ActionRouteHandler; instances of this type are registered with the RoutingServices as the handlers for all action related routes. This is non-configurable, because this specific handler is used to maintain a collection of IActionHandler(s) registered for the particular route. You will normally not deal with this class directly, as the ActionService consumes it internally. However it is good know.

 Action ServiceActionServiceClass

The Action Service wraps around the Routing Service, but unlike the Navigation Service it has a fire-and-forget type of consumption semantics. As I've said before, calling on an action doesn't return any value whatsoever, so you might have ten registered handlers for a specific action or you might have zero handlers but there are no indications about the handles count or the result as far consumer's API is concerned. Now, I've explained the two-step registration process, which separates the registration of the route/Url and adding or removing of the related IActionHandlers - think .NET events, where we have the event definition and adding/removing of the event handlers. And you can register or un-register handlers by identifying it through the route name or the mapped Url, either way. Also, you also check if an action is already registered using the IsActionUrlRegistered or IsActionRouteRegistered methods.

The Process method is the entry point to get an action executed, it has two overrides, one that uses the registered handlers and another one which can execute against a given IActionHandler instance. In the second option, only the given handler is called for and not the registered ones, however as of now this is executed synchronously but this will change in the future to an asynchronous execution model. Furthermore, the option that you can execute an action against a handler gives you an almost ICommand like capability, the difference being the loosely-coupled Url based identifier. And particularly for this scenario, you can use the ActionDelegate type which implements the IActionHandler interface which gives you a simple wrapper to use from your ViewModel (by exposing it as a property and binding within the UI). However do note, even if you use your custom handler for an action the Url must have been registered - this is by design.

Attributes Mapping

Like with the Navigation Services, we also get an extensible AOPish style functionality to auto-register actionable Urls. This functionality is accessed by the MapAssemblyActions and MapLoadedAssembliesActions methods on the ActionService class.
 Attributes for Registering Actions
This works in a similar way to the Navigation related attributes, the ActionService when asked to auto-map actions from a given assembly it looks for the MapActionBaseAttribute type on all public types. As you can see the attribute has an Url property and resolves an IActionHandler - which are the two things required to get an action route and handler setup. It is a very simple system, and you can extend this by your custom implementation of the base attribute, to address your custom loading/mapping strategies. The other benefit of using the attributes is that it is not statically registered, rather is runtime based which you exploit to your advantage. For example, if the user is not Admin we don't load and map the actions usable only by the admin or you could load different UIs identifiable by the Url but we just exchange the assembly yet the identifiers stay the same.  Below is a simple snippet from the demo app that gets itself registered via the MapActionHandleAttribute, and is used to navigate externally.

[MapActionHandler("System/NavigateExternal/{URL}")]
public class NavigateExternalAction : IActionHandler
{

    const string URL_KEY = "URL";
    const string ORKPAD_COM = "http://www.orktane.com";
    const string NROUTE_CODEPLEX = "http://nRoute.codeplex.com";

#region IActionHandler Members

    public bool CanHandle(IActionDefination action)
    {
        return true;
    }

    public void Handle(IActionDefination action)
    {

        // we need to use the dispatcher to navigate to external addresses
        action.Request.Dispatcher.BeginInvoke(new Action(() => 
        {

            var _urlKey = action.ParsedParameters[URL_KEY].ToString();

            if (string.Equals(_urlKey, "Orkpad", StringComparison.OrdinalIgnoreCase))
                HtmlPage.Window.Navigate(new Uri(ORKPAD_COM, UriKind.Absolute));

            else if (string.Equals(_urlKey, "nRoute", StringComparison.OrdinalIgnoreCase))
                HtmlPage.Window.Navigate(new Uri(NROUTE_CODEPLEX, UriKind.Absolute));

        }));
    }

#endregion

}

This finishes another part of the laborious documentation, I have three/four more big topics to go. However, I'll take a detour to rather write up samples and a couple of quick starts on the core features. Anyhow, I hope this post underscored how the actions infrastructure in nRoute helps to further and easily "demarkify" business-functionality from the UI.

Posted by Rishi on 06-Apr-09 6:47 AM, 17 Comments

In this post, I want to describe how the Navigation Service works and how it relates to the all important INavigationHandler. To be honest, the Navigation Service is a very thin wrapper around the Routing Service; but it is semantically very important because it puts a context around the consumption of the routing responses - for navigation purposes obviously. I'll take on each part related to the Navigation functionality in a piece by piece manner, but first below is what I consider my mind-map relating to Navigation and Routing in nRoute:

Click for a Larger Picture

Navigation Requests

Basically all requests constitute of two principle things, one the Url and two a name-value collection; and this is accordingly reflected in the IUrlRequest interface. The other member in that interface is the ServiceState property, which is supposed to be for internal use of the services to carry any service-specific data. 
NavigationRequests
Now, the only thing that the NavigationRequest type adds is the the NavigationMode property, which is an enumeration that tells the container what kind of request (back, forward etc) we are dealing with - it's usage is container specific and some containers totally ignore it. However, I made it a first level concept to enabled browser integration and minimize ambiguity. All the same, for most purposes you will only need to be concerned with the the Url alone. In fact I suggest that you should try and minimize the need for passing name-value parameters, and consider using defaults parameters if necessary. One other point, the Url that you register or use should not contain a "?" and it should not start with either "/" or "~" (these are trimmed on use, but avoid them), I've carried these requirements intact from asp.net routing specifications as it made the relative Urls sort of consistent.

Navigation Response

The navigation response is based on the IUrlResponse interface, that defines five almost self-describing properties. The important ones are Content, which holds the actual result. And the other is ResponseParameters, which is basically a merged name-value collection of the original request parameters, the default parameters set while defining the route, and the parsed token-parameters from the Url. And priority level for merging is such that request parameters override Url parsed parameters, which in turn override the default parameters.
NavigationResponses 
The navigation response adds one things, which is the NavigationStateManager property of type ISupportNavigationState interface. The ISupportNavigationState is a mechanism to participate in state management but participation is optional, and also the reason it is separated from the actual result is to facilitate M-V-VM like pattern. So for example, the response itself can be an Usercontrol, but it doesn't have to implement the state management, whereas it's ViewModel can do that or a parent controller can do that. One last thing, the Error property only holds exceptions that are occur in the course of getting the actual response (from the IRouteHandler) and not say from an invalid Url.

IRouteHandler Implementations

You can think of the IRouteHandler as the your end of the bargain, that when posed the Url-specific request provides the response - which is basically the same in asp.net routing or MVC.  Now you can create your own handlers very easily, but I provide two build-in implementations - one specializes in loading assembly-embedded resources like images, xaml-only files, text files etc. The other, more general purpose one, takes in two delegates yielding the response and optionally an ISupportNavigationState object.   

// NavigationRouteHandler Constructor
public NavigationRouteHandler(Func<ParametersDictionary, Object> responseResolver,
           Func<Object, ISupportNavigationState> navigationStateManagerResolver) { ... }

In the first parameter of the constructor signature above, we pass into the Func the request's name-value collection and it is supposed to return the result, which we then pass into the second Func to get the state management related interface. However, like I said before, the second parameter to resolve the state is optional. Let me stress this again, you can provide your own implementation as per your needs, say for example a handler that dynamically downloads assemblies on demand.  

INavigationHandlerINavigationHandlerInterface

The INavigationHandler Interface is a very simple interface, almost ICommands'que. The ValidateRequest is asked as to if the handler can process the request, if false it yields a NavigationResponse will null content and Cancelled status. The ProccessResponse, is equally simple in that it is asked to process the response. Now, the inbuilt navigation containers all use this to get the response and display it, but if you were devious enough you will know that it doesn't have to be that. You could for example use this as a signalling mechanism or even get data - and you can get even more creative if used with navigation behaviours I mentioned in my last post. However, you must be careful because the calls to the handler are all synchronous, which means you can potentially block the UI thread inappropriately.

Navigation ServiceNavigationServiceClass

Like I said earlier the Navigation Service is a wrapper around the Routing Services, but it importantly provides the capability to inject responses into through the INavigationHandler interface. And it does use that mechanism, when you use the Navigate method that takes in a NavigationRequest and an INavigationHandler - to which it will given back the response to process. The other main method is Resolve, which takes in a NavigationRequest and gives out a NavigationResponse. That is important in a way, because it means you can get the response from without having to go through a handler. So you have two ways to get the response, but you will almost always use the Navigate method which in a manner of speaking injects the response into the passed in INavigationHandler container.

The MapRoute method provides a couple of different ways to register a Navigation Route, some of which I shown before. However, truth be told, in as far as registering routes you can totally forgo the NavigationService and register against either the RouteTable or the RoutingService itself. Lastly, the MapLoadedAssemblieRoutes and MapAssemblyRoutes methods provide support for mapping Url to content using attributes. MapLoadedAssembliesRoutes enlists all loaded assemblies and passes them to the MapAssemblyRoutes method which auto-registers navigation routes - as described next.

Attributes Mapping

In a lot of use-cases the "strong-by-convention" way of registering routes can frankly be burdensome, so I created an extensible AOPish way to auto-register Url and it's required IRouteHandler.

  MapNavigationAttributes

The shown MapNavigationBaseAttribute is the attribute the NavigationService looks for when asked to map an assembly, and then to register the navigation route it calls upon the attribute's ResolveHandler abstract method. That is very simple, but what this also means is you can create your own derived attributes to suit your loading strategy, say one that uses some kind of dependency injection tool. And the other obviously useful thing about attributes is that it is registered at runtime, so you can say load in a different assemblies on a per user basis (like don't load Admin related assemblies when the user is a not an Admin). I'll also show in another post a derived attribute that does M-V-VM automagically for you.

That's it for now, these posts are really getting long and dry - but the drudgery is necessary because these are meant to be persudo documentation for nRoute. Anyhow, I hope you have learned how the whole request in and response out thing works. I'll leave you with some immortal words from Karate Kid:

Daniel LaRusso: Hey, what kind of belt do you have?
Mr. Kesuke Miyagi: Canvas. J.C. Penny. Three ninety-eight. You like.
Daniel LaRusso: No, I meant...
Mr. Kesuke Miyagi: In Okinawa, belt mean no need rope to hold up pants.

Posted by Rishi on 04-Apr-09 3:27 PM, 17 Comments

As weird as the title sounds, I love what behaviours using attached properties bring to Silverlight and WPF. They are kind of what Javascript is to HTML elements - the wonder that extends controls beyond their limited initial intentions.

Now, with respect nRoute, what I did was map every event in almost all the controls in SL 2 base library to do three things, one navigate, two take an action and three execute an ICommand (sorry this is like a little mantra I keep repeating). The core point being, this is a very extensive body of abstraction that should help with over 75% of your UI interaction at the very least. Also, this is based on the Prism 2's behaviours' code pattern, but in their instance they were limited to Buttons - here it is starts right at the bottom from UIElement. Tabulated below are the behaviours available for events in nRoute:

Control Behaviour for Control's Event NAV ACN CMD
UIElement GotFocus x x x
  LostFocus x x x
  KeyDown x x x
  KeyUp x x x
  LostMouseCapture x x x
  LeftMouseButtonDown (named MouseDown) x x x
  LeftMouseButtonUp (named MouseUp) x x x
  MouseEnter x x x
  MouseLeave x x x
  MouseMove x x x
         
FrameworkElement BindingValidationError (Silverlight Only, N/A in WPF) x x x
  LayoutUpdated x x x
  Loaded x x x
  SizeChanged x x x
         
Control EnableChanged x x x
         
ButtonBase Click x x x
         
RangeBase ValueChanged x x x
         
Selector SelectionChanged x x x
         
ToggleButton Indeterminate, Checked, UnChecked (into one StateChanged Event) x x x
         
TextBox SelectionChanged x x x
  TextChanged x x x
         
PasswordBox PasswordChanged x x x
         
Scrollbar Scroll x x x
         
Image ImageFailed x x x
         
Timeline* Completed x x x
         
Abbreviations: NAV = Navigation Support, ACN=Actions Support and CMD = ICommand Support

Believe it or not these are almost all the events exposed by SL2 base-library controls with exception of four events (Tooltip's opened and closed events, and ComboBox's DropDownOpen and DropDownClosed events) and three other controls' (MediaScaleImage, MediaElement, and Thumb Control) events. Note, the Timeline object is a DependencyObject and not an UIElement derivative, so it exhibits a bit different usage semantics (explained ahead).

How do we use it? In Visual Studio, you import the relevant namespaces and basically attach them to what ever element you want. Below we have behaviours attached to a Button, Border, ItemsControls and it can be almost anything deriving for any of the classes listed above so thing like ListBox, CheckBoxes, Storyboard or your custom controls.

Declare XML Namespaces
Showing Navigation Behaviours Avaliable to a Border Control  Showing Loaded Action Behaviours Parameters for an Items Control

Showing Command Behaviours Parameters Avaliable to a Button Control
Samples of attached behaviours on various controls

Let me explain the three behaviours attached to the buttons in the screenshot just above. In the first case we have attached a behaviour that on the click event of the button executes the NewOrderCommand. In the second example, we have an action behaviour attached to the mouse-enter event of the button, and the action is identified with the Url shown. Also the action can have zero or more handlers at the back end, which can do whatever as necessitated by the business logic. Lastly, we are attaching a behaviour that will execute if there is a binding validation error, and it will navigate to the shown Url. Now, where (as in which container) the navigation occurs is configurable, but you can say put up a side panel that could show the content from that Url.

I just want to raise this point here again, you can attach to all the listed events above and execute any of the three categories of behaviours from just about any control, including your own. If you see the code for the demo app posted, I used these behaviours and had exactly zero code-behind the xaml files (except where I had to do element to element binding or triggering property updates - both these facilities are now there in SL3). This is very significant for both M-V-VM design pattern, and in general to raise the level of abstraction (along with flexibility, changeability etc benefits) from having to deal with Urls rather than instance types.

Now, the "bhv" namespace imported above is a bit special, it is specifically used to attach multiple behaviours. And because of how the internals of Silverlight work, it has one limitation which is you can't use binding expressions with it (the same is the case with the timeline behaviour), but you can use static resources binding expressions just fine. Below is an example of multiple bindings where the arrow keys are mapped to some action Url.

<!-- KEYBOARD ACTION MAPPINGS, MAPPED TO/WITH THE BORDER -->
<Border>
    <bhv:Behaviours.Multiple>
        <bhv:BehavioursCollection>
            <bhv:KeyDownAction Key="Up" ActionUrl="Move/North" />
            <bhv:KeyDownAction Key="Right" ActionUrl="Move/East" />
            <bhv:KeyDownAction Key="Left" ActionUrl="Move/West" />
            <bhv:KeyDownAction Key="Down" ActionUrl="Move/South" />
        </bhv:BehavioursCollection>
    </bhv:Behaviours.Multiple>
</Border>

Next, I wanted to explain the common properties you will see for each of the three categories of behaviours. As an exception note, KeyUp and KeyDown behaviours have two added properties specifying the key and the key modifier, rest all have the same properties as show below.

Navigation Behaviours

NavigationBehaviours

  • NavigateHandler: Here you can specify (rather bind to) any object that implements INavigationHandler to handle the navigation response. Note this is also a way consume navigation requests and responses in non-visual ways.
  •  NavigateHandlerElementName: Alternatively if the handler is an element in the user interface you can give it's element name and it will be asked to handle the result of the navigation. NavigateParameters: These are name-value collections you can pass with the request.
  • NavigateUrl: Obviously the Url to navigate to, and it is required.
  • NavigateUrlStringFormat: This is used to provide a format for the NavigateUrl property, it is similar to what was introduced in .NET 3.5sp1 binding and it helps in that it can avoid the use of type convertors in some scenarios.

One thing to know, and this is important, is how the behaviour chooses the container that will handle the response. Firstly, if you have specified the handler (either by binding or by an ElementName) it will just use that and life is simple. If you do not specify, it will look in it's visual tree first and try and find the first parent that implements INavigationHandler interface. This is also means that it works kinda like a browser whereby when you click a link the immediate most container (think IFrames here) handles the navigation for you. If no handler is found in the parental visual tree, it will look at the current application object and see if it has is a registered container (of type INavigationContainer) and use that. If it still doesn't find a container at the application level, well it gives up and throws an exception.

Action Behaviours

ActionBehaviours

  • ActionHandler: Here like above you can specify (rather bind to) any object that implements IActionHandler interface to handle the action request. Note the handler doesn't need to be registered against with the ActionService, and so this is also a way to bypass the registered Url handlers ie. they will not be called.
  •  ActionHandlerElementName: Alternatively if the handler is an element in the visual tree you can give it's element name and it will be asked to handle the action. Again, as above this is a way to bypass the registered action handlers.
  • ActionParameters: Like before these are name-value collections you can pass with the request.
  • ActionUrl: Quite intuitively the Url for the action, and it is a required parameter.
  • ActionUrlStringFormat: This is used to provide a format for the ActionUrl property, and helps in that it can avoid the use of type convertors sometimes.

The resolution of the action is basically similar to the navigation behaviours, but with exception that it doesn't look up in the visual tree for anything that implements IActionHandler and directly goes onto any registered handlers for the action Url.

Command Behaviours

CommandBehaviours

  • Command: You basically specify, like WPF, any object that implements the ICommand interface.
  • CommandParameter: And the accompanying parameter can be specified here.

In this case the hooking up is rather direct, you must have specified the ICommand implementing handler and the behaviour will execute it for you whilst also passing in the parameter. This helps overcome the lack of build-in support for ICommand but also extends the usage semantics in WPF.

As this has gotten quite long I'll skip the demo for another post, but I hope you can see how these behaviours bridge the element's events with a handler/consumer either directly (like with ICommands) or indirectly (via Urls) saving you a lot of work and raising the abstraction level. In fact off the 35,000+ lines of code in nRoute 60% are dedicated to bring you these behaviours (over 75 of them) - so it's quite a bite.

Posted by Rishi on 03-Apr-09 3:05 PM, 19 Comments

Categories: Architecture, nRoute

200px-Close_Encounters_posterIf I could annotate a tag line for the software industry as a whole, I would put down "we are in the business of abstractions". And perhaps, if I was in marketing for the software industry, I would append that with "because you can't have it all". Well, more to the point, in my last post I mentioned a lot of working parts that constitute the nRoute Framework while also repeatedly mentioning there is a higher level API, and that is what I want to cover in this post.

First, how is nRoute an abstraction of a "higher kind"? In two ways, it abstracts resources and actions in the form of URLs (or more correctly as URL requests). So for example you want to show the customer page you abstract it as a relative Url like "Customers/Details/StevenSpielberg/" and similarly you want to abstract a Log Entry action with a relative Url like "System/Log/Critical/" whist passing in the actual log object in a name-value collection with the request. This also represents classic loose coupling, and what it gives you is the ability to link-up actual .net objects/controls in a systematic and structured way without having direct reference to each other (very much like hyperlinks) - of which I am sure you know benefits. Another characteristic this yields, is resilience to both changes and partial break-downs for a lack of a better word. Think about how the Internet works, just because a link has 404'ed it doesn't mean the entire system comes with an unhandled exception - it still works albeit without the missing resource. And just to point the obvious, with Urls if you say put in a new user control for the the customer's details page you wouldn't have to move a dime elsewhere ,as long as it still registered at the same Url.

Firstly, let me show you how you consume Urls within the UI. Below is a simplified xaml snipped from my demo app, in which you have a "Home" persuado button (Border actually) that links to the "Home/" Url.

<!-- nav NAMESPACE -->
xmlns:nav="clr-namespace:nRoute.Behaviours.Navigation;assembly=nRoute.Silverlight"

<!-- HOME BUTTON, with STYLES -->
<Border Style="{StaticResource HomeButtonBorderStyle" nav:MouseUp.NavigateUrl="Home/">
	<TextBlock Style="{StaticResource HomeButtonTextStyle}" Text="HOME ." />
</Border>
As you can see the xaml is very simple, we are using a border to wrap a text block that reads home with a dot. What is interesting is the "nav" namespace, which brings into play attached properties that allow us to register a behaviour with the border control - the behaviour effectively says on "MouseLeftButtonUp" event navigate to this Url. That's it, and you are done as long as the Url is registered to return a visual it should work. The question of how it works, I'll need to defer to another post but basically in this case we have a Navigation Container that is registered at the application level which would handle this request.

Second example is a xaml snipped again from the demo app, and it's for registering actions to take on certain keyboard events. If you have seen the sample app, it has 3 workspaces (aka blades) onto which you can navigate, however by design it is actually configurable from 1 to 9 workspaces.  So in the code below we register keyboard shortcuts for shifting from one blade/workspace to another (though in some case it does conflict with the browser shortcuts).

<!-- bhv NAMESPACE -->
xmlns:bhv="clr-namespace:nRoute.Behaviours;assembly=nRoute.Silverlight"

<!-- KEYBOARD ACTION MAPPINGS, MAPPED TO/WITH THE ROOT USER CONTROL -->
<bhv:Behaviours.Multiple>
    <bhv:BehavioursCollection>
        
        <!-- WORKSPACES 1 to 9 MAPPED WITH NUMBERS  -->
        <bhv:KeyUpAction ActionUrl="Workspace/Actions/Select/1" Key="D1" KeyModifiers="Control" />
        <bhv:KeyUpAction ActionUrl="Workspace/Actions/Select/2/" Key="D2" KeyModifiers="Control" />
        <bhv:KeyUpAction ActionUrl="Workspace/Actions/Select/3/" Key="D3" KeyModifiers="Control" />
        <bhv:KeyUpAction ActionUrl="Workspace/Actions/Select/4/" Key="D4" KeyModifiers="Control" />
        <bhv:KeyUpAction ActionUrl="Workspace/Actions/Select/5/" Key="D5" KeyModifiers="Control" />
        <bhv:KeyUpAction ActionUrl="Workspace/Actions/Select/6/" Key="D6" KeyModifiers="Control" />
        <bhv:KeyUpAction ActionUrl="Workspace/Actions/Select/7/" Key="D7" KeyModifiers="Control" />
        <bhv:KeyUpAction ActionUrl="Workspace/Actions/Select/8/" Key="D8" KeyModifiers="Control" />
        <bhv:KeyUpAction ActionUrl="Workspace/Actions/Select/9/" Key="D9" KeyModifiers="Control" />
        
        <!-- OTHER MAPPING -->
        <bhv:KeyUpNavigate NavigateUrl="Home/" Key="H" KeyModifiers="Control" />
        
    </bhv:BehavioursCollection>
</bhv:Behaviours.Multiple>
Again we are using attached behaviours, and in this case we are attaching to the root Usercontrol, which is also used as the root visual of the app - so kinda this is like global keyboard mapping if you may. As apparent, we are importing the "bhv" namespace  which allows us to register multiple behaviours against a single element (with a caveat). And we are attaching KeyUp events for Ctrl+(Digits 1 to 9), against an action Url that was registered as "Workspace/Actions/Select/{WorkspaceIndex}". The action handler for that Url basically gets the token WorkspaceIndex and it changes the active workspace using the workspaces' ViewModel; pretty simple really, and it gets rid of the ugly code-behind file like forever. There is another mapping shown below that, which is using Ctrl+H KeyUp events to navigate to the "Home/" Url. Now, equally well you can do all this with code and but you'll have to use the NavigationService and ActionService static classes for the same.

Now, there are a lot of attached behaviours in nRoute to do three main things:

  1. Navigate to an Url
  2. Take an Action
  3. Use an ICommand

You can attach these with almost all Silverlight build-in controls events, and I mean almost all. There is so much detail in these behaviours that I'll have to post it separately, but suffice to say, if you don't use nRoute take out the ICommand behaviours at least and use them - you will spare a lot code and time.

nRoute Demo App : Future Desktop
The demo app, available with complete source code, makes uses of all the features mentioned here.

The requirement for using the enlisted features is registering navigation and action Urls (with handlers to be precise). In my previous post I've shown how you can register via code, but now, I wanted to show the "higher abstraction" version of the same.

using System.Windows.Controls;
using nRoute.Navigation;

namespace nRoute.Samples.FutureDesktop.Pages
{
    [MapNavigationContent("Home/", "Home Page")]
    public partial class HomePage : UserControl
    {
        public HomePage()
        {
            InitializeComponent();
        }
    }
}
This is the code behind for the Home Page of the demo app, and there is nothing special except for the little attribute named MapNavigationContent. And it does exactly that, maps the resource (you have put it above-on) as an Url and also gives the page a title which is pretty self-evident here. And that's really it; moreover if you page were to implement either ISupportNavigationState or IResolveNavigationState it would also pick that up and use it for state management automatically. One other way to use this is to put it on your ViewModel class and specify the "NavigationContentType" parameter of attribute, and it will use the given NavigationContent type as the content and target type (of the attribute) as possibly the ISupportNavigationState provider. One additional point, you can put multiple of these attributes to respond to multiple Urls on the same class.

Now  registering actions is purposefully very similar to what is shown above. Here we have an action handler class that handles the foreshown KeyUp events. Also, note it doesn't point to any particular KeyUp event or any potential triggering mechanism, it just handles the action and the Action Service + behaviours take care of the plumbing infrastructure.

[MapActionHandler("Workspace/Actions/Select/{Number}")]
public class WorkspaceSelectionAction : IActionHandler
{

    const string NUMBER_KEY = "Number";

#region IActionHandler Members

    public bool CanHandle(IActionDefination action)
    {
        return (action.ParsedParameters.ContainsKey(NUMBER_KEY));
    }

    public void Handle(IActionDefination action)
    {
        // if we can't get the value
        int _newIndex = -1;
        if (!Int32.TryParse(action.ParsedParameters[NUMBER_KEY] as string, out _newIndex)) return;
        
        // we get the view model and check if the index is avaliable
        var _viewModel = ((App)Application.Current).WorkspacesViewModel;
        if (_newIndex < 0 || _newIndex > _viewModel.WorkspacesCount) return;

        // else we activate, note the use of the dispatcher
        action.Request.Dispatcher.BeginInvoke(() => _viewModel.ActivateWorkspace(_newIndex));
    }

#endregion

}
The one important thing in the code is the use of the dispatcher, since actions are called-upon asynchronously and off the UI-thread, we need to use the dispatcher to effect any changes onto the UI - that's just the standard platform stuff.  Plus like the navigation mapping attribute, you can apply multiple attributes to the same handler. Also note, for demonstration purposes I separated this from the Workspaces' ViewModel, but you could just as well have tacked it onto the ViewModel class using an ICommand.

How do the mappings get registered? Well, in this case we make two calls on the action and navigation services as show below. This is from the demo app's App class, where we override the custom base applications class's register methods which kind of akin to overriding in global.ascx class in asp.net:

protected override void RegisterNavigationsRoutes()
{
    NavigationService.MapLoadedAssembliesRoutes();

    // we register the images
    NavigationService.MapRoute("Images/HeartYourWeb",
        new NavigationResourceHandler("Images/HeartYourWeb.xaml", NavigationResourceHandler.XamlLoader));
    NavigationService.MapRoute("Images/MixLab",
        new NavigationResourceHandler("Images/MIX09_Color_RGB_tag.xaml", NavigationResourceHandler.XamlLoader));
    NavigationService.MapRoute("Images/MixLogo",
        new NavigationResourceHandler("Images/MIX09Logo.xaml", NavigationResourceHandler.XamlLoader));

}

protected override void RegisterActionsRoutes()
{
    ActionService.MapLoadedAssembliesActions();
}
The two evidently important calls are MapLoadedAssembliesActions and MapLoadedAssembliesRoutes that basically enumerate all public types and look for the aforementioned attributes. You can also see, I am registering three xaml-only resource files that don't have a code-behind file in the same call. Moreover, I purposely chose not automatically map loaded assemblies, so that you can use whatever loading strategy that suits you - including dynamically loading and mapping assemblies. All in all, this is a very simple way of doing the whole kibosh of Url routing et al., but using attributes for mapping has limitations in that you can't specify default or constraints for Url tokens on attributes.

I hope I've show how you can perhaps work at a higher abstraction with respect to the constructs and plumbing in nRoute. Unfortunately, there is a lot more to show and tell, and I defer again to future posts especially with respect to using this with M-V-VM and custom loading/mapping strategies. My next post will go much deeper into behaviours and how they really are "code-savers" in the ever enduring adventures of "abstractions of the higher kind".

Posted by Rishi on 03-Apr-09 2:17 AM, 15 Comments

Categories: nRoute, Architecture