Couple of days ago I published a sample app in Silverlight that fronted Netflix’s oData API – well, now I’ve ported the same app into WPF again making use of nRoute Framework. It like before demonstrates how you can build an end-to-end application using nRoute’s navigation framework and MVVM related features-set on WPF.

As this is just a port, the preceding Silverlight based step-by-step guide is fully applicable here; besides templating and some implementation details the through-process is about equivalent – and so in this post I won't go through the nitty-gritty of designing the app, rather I’ll just discuss the broader ideas, issues I faced, and changes I had to make to up-port it to WPF.
Design
The general design approach is about the same as before, the application layout is divided into three sections, one for selecting a top-level feature, two for showing a listing per the selected top-level feature, and lastly one for for showing the content or details – and they all are stitched together using nRoute’s navigation framework.

Like before again, we source our top-level features from a SiteMap declaration – this time though it is slightly altered as we’ve added a language-based listing feature and changed how the “about” view is displayed.
1: <n:XamlSiteMapProvider>
2: <n:SiteMap>
3: <!-- ROOT NODE -->
4: <n:SiteMap.RootNode>
5: <n:NavigationNode>
6: <n:NavigationNode Title="genres" Url="Content/Netflix/Genres/"/>
7: <n:NavigationNode Title="movies" Url="Content/Netflix/Movies/"/>
8: <n:NavigationNode Title="people" Url="Content/Netflix/People/"/>
9: <n:NavigationNode Title="languages" Url="Content/Netflix/Languages/"/>
10: <n:ControllerActionNode Title="about" Url="Content/Windows/About/"/>
11: </n:NavigationNode>
12: </n:SiteMap.RootNode>
13: </n:SiteMap>
14: </n:XamlSiteMapProvider>
Starting Point
Rather than starting from scratch, this time I opted to use the recently previewed project and item templates for nRoute – using the navigation templates (shown below) I was able to get a quick/working start point with a nice Metro/Cosmopolitan theme to boot.
And thereon it didn’t take much effort to get going, I changed the SiteMap to reflect my needs, and added two named navigation containers, and with little templating I managed to wrangle the Views and ViewModel from the Silverlight project into looking something like:

oData, oh!
Though the UI was up and running quickly there was one big issue, the problem was that in Silverlight the “default” WCF DataService API is asynchronous whereas in WPF or .NET in general the “default” API is synchronous which means it blocks on the UI thread. And so I had to change the data-access strategy to use the fugly Begin/End asynchronous API, which in hindsight I should have done in Silverlight but then again I had not pre-planned to have a WPF port. The change wasn’t that hard since things were nicely isolated in the ViewModels, however as a consequence I was forced to fundamentally change how we stitched various Navigation Views.
Previously in Silverlight we were passing along lists as navigation parameters, and these lists came with a built-in continuation of sorts (with the LoadNextPartialSetAsync method) which allowed for more results to be evaluated, however in the .NET version there is nothing quite equivalent to that – so rather then passing results I decided to pass along a LINQ “query” that the receiving ViewModel could asynchronously evaluate. This approach is what I earlier mentioned as passing metadata to realize the data as opposed to passing directly consumable data – and this is a very loosely coupled but effective way to block-build your application. Consider in the figure below, when one selects the “Chinese” language from the languages listings (on the left) we create a DataServiceQuery that gets passed to the content View’s ViewModel, which then executes it get the movies listing (show on the right):
One learnable part here is how to source and bind the “query” from the ViewModel, here we are using a ValueConverter which goes back to the ViewModel to create the query as per the selected item. We use something called a ValueConverterRelay in nRoute. What a relay can do is to stand-in as a static ValueConverter but outsource its evaluation logic, and in this case we want it sourced from our ViewModel. There are two steps to this, first declare a relay resource with a key, just as you would any value converter:
1: <UserControl.Resources>
2: <n:ValueConverterRelay x:Key="TitleQueryConverter" />
3: </UserControl.Resources>
Second, we drag-drop a BridgeValueConverter behaviour that essentially bridges the value relay (declared above) to a IValueConverter property in our ViewModel. As as you can see below it binds to a excruciating named LanguageToTitleQueryConverter property in our ViewModel:
1: <i:Interaction.Behaviors>
2: <n:BridgeValueConverterBehavior
3: ValueConverterRelay="{StaticResource TitleQueryConverter}"
4: ConverterSource="{Binding LanguageToTitleQueryConverter}"/>
5: </i:Interaction.Behaviors>
And I might be drifting into TMI (Too Much Information) category, but below is the IValueConverter implementation (using nRoute’s built-in generic converter) from our ViewModel that transverses from a Languages to a Titles selection – and this is good to know because oData does not support Select Many queries and so this is essentially the only way to do predicated cross selects:
1: public ValueConverter<Language, DataServiceQuery<Title>> LanguageToTitleQueryConverter {
2: get {
3: if (_converter == null) {
4: _converter = new ValueConverter<Language, DataServiceQuery<Title>>(
5: (l) => (DataServiceQuery<Title>)(
6: from _l in base.Context.Languages.IncludeTotalCount()
7: from _t in _l.Titles
8: where _l.Name == l.Name
9: select _t));
10: }
11: return _converter;
12: }
13: }
Also, relays are very useful in the MVVM world where your defining logic resides elsewhere or in cases where you, like above, want to something contextually; and in nRoute we have two additional types of relays called ValueRelays and CommandRelays. One last point about this, relays can also be sourced from your code-behind, have a look at the various ValueConverters relays I’ve used in the “TitleView” – you might never ever need specialized IValueConverters implementations anymore.
Using Controllers
Because I’ve been repeatedly asked about it lately, I just wanted to quickly show how you can use Url based controller actions – if you have a look at line 10 in the SiteMap declaration above you will find we’ve declared a ControllerAction node that maps to a certain “Content/Window/About” Url – executing this action brings up the following dialog:
So controller actions are basically Url-addressable code-blocks, and they are purposefully designed to mimic the same semantics as controllers in ASP.NET MVC. If you are conversant with MVC then the following should be quite parsable, it is the “about” dialog showing controller definition in its entirety:
1: [MapController("Content/Windows/{Action}/")]
2: public class WindowsController : Controller
3: {
4: public void About()
5: {
6: var _window = new AboutWindow();
7: _window.ShowDialog();
8: }
9: }
In line 1 we earmark the class as a “controller” which responds to the specified Url, with the provision that the “{Action}” token is substituted by any similarly named method within it. Also, do note that it is a must for a controller to inherit from the either Controller or ControllerBase class. And as you can tell within the About method we are just instantiating and showing the dialog.
WPF Issues
With data-access and data-passing issues resolved the port was essentially done, except we had to replace the default and stylistically mismatched chrome with a custom chrome that rendered its own drop shadows and managed both the resizing and maximizing logic:
Also coming from prolonged Silverlight development I felt that WPF control templating was unnecessarily muddled, for example in WPF 4 we now have options of templating using Data Triggers, Event Triggers, and VSM based Parts and States Model. The problem is in some instances you have states but no parts, while in other controls you might have some parts declared but no corresponding states, yet in other controls all you get is a opaque chrome element rather than individual elements that constitute a control – all this relatively makes Silverlight based templating a breeze. Also in what is often called Fluid UI, WPF lags Silverlight in having the necessary hooks to create the rich/fluid controls – case in point the ListBox. And, despite the much advertised improvements in text rendering, I couldn’t find the right text hints and options combination to bring WPF text rendering anywhere near GDI level clarity. Lastly, in binding expressions the use of StringFormat functionality was also broken as in some places it simply refused to take hold no matter what I tried.
nRoute Issues
In as far as nRoute is concerned I ran into two issues with WPF, one was that referenced assemblies are lazy loaded in WPF which can create timing issues as far mapping of declared resources on initialization is concerned – this isn’t an issue with Silverlight because xap files include a manifest of all known assemblies (loaded or not). In WPF, nRoute relies on the AppDomain to see which assemblies are load, hence the timing issue – the solution (for now) is really quite simple just enlist the assembly in SiteArea’s declaration and set InitializeOnLoad to be true or alternatively you can manually map the assembly in code (line 5 below) as we did in App.xaml file:
1: // in App.xaml
2: protected override void OnStartup(System.Windows.StartupEventArgs e)
3: {
4: base.OnStartup(e);
5: AssemblyMapper.MapAssembly(typeof(NetflixDataContext).Assembly);
6: }
The second issue I faced was also a timing issue – it seems WPF attached behaviours are initialized post binding whereas in Silverlight they are resolved before binding takes place. This creates a number of subtle issues, primarily leading to incompatibilities between your Silverlight and WPF code – for example, in Silverlight I am able to restore navigation state before binding takes place, whereas in WPF the binding is resolved before I can restore state, meaning I need to always ensure a property change notification is raised post restoring state. These are subtle issues but they have consequential effects over assumptions your make and how you structure your code’s logical-flow. Now, one of the things I used to stem the differences was to use View lifecycle related commands available with BridgeViewModel behaviour in nRoute, for example:
1: <i:Interaction.Behaviors>
2: <n:BridgeViewModelBehavior LoadedCommand="{Binding LoadDataCommand}"/>
3: </i:Interaction.Behaviors>
By binding to LoadedCommand property above I am able to execute a “LoadDataCommand” ICommand in my ViewModel – and it is raised precisely when the View is loaded hence the name. These are so-called lifetime event commands, and they help you correlate View’s lifetime events to the UI-free world of ViewModels.
Fluid Thoughts

Overall I am pleased with how well nRoute concepts translated one-to-one from Silverlight, the changes were all more or less either due to differences in WCF Data Services or subtle WPF binding variances. The logical and broader flow was about the same – and application flow here seemed to be a good fit to “Metro” style application as pioneered by the Zune client. Though this demo is far from a fluid experience, it has all the underpinnings required for a real-world application. Another notable is how well-behaved the application is in terms of memory consumption – a somewhat pesky issue for WPF applications in general. I believe it is well-behaved because using nRoute’s navigation capabilities we only ever have two visible Views at any given time, every other prior View is deallocated and only its state held. Combined all that, I hope this application ably demonstrates the possibilities of nRoute on WPF even though it is early days.
Run the nNetflix Application from http://www.orktane.com/nRoute/nNetflix/
Note, it uses ClickOnce but does not install on your computer
Download the source code from Codeplex
Posted by Rishi on 11-Jul-10 11:48 AM, 22 Comments