Nico's digital footprint

I grew up in the nineties, that makes me awesome by default

A practical guide to MVVM (Light)–Part 2

by Nico

A practical guide to MVVM (Light) – Part 1

In part 1 I’ve shown you how to setup a new Windows Phone project with MVVM Light, how to hookup everything and we’ve seen what databinding is and how it works. In this part we’re going to build on that same project, delving a bit deeper into MVVM in a practical way.

Intro

In part 2 we’ll have a look at how to navigate from a list page, like the one we’ve created in part 1, to a detail page. We’ll need to inform the viewmodel on what item was clicked so that it can fetch more detailed information from the datastore. We’ll also have a look at value converters, a feature not really MVVM related but one that’s really important so I’m including it here anyway.

Navigation

There are a few ways to get navigation done in a Windows Phone app. You can use a NavigationService class for example. A class that can get injected via SimpleIoc and that has a .Navigate function, the Cimbalino Toolkit has one build-in for example. One other way to do navigation without delving into code-behind code in the view is by using Behaviors and Actions in XAML. Don’t worry, you don’t need to remember the exact syntax as long as you have Blend.

Open up the MainPage.xaml of our Part 1 project in Blend and have a look at the Assets Tab. (Quick tip: if you want to open a certain page in Blend, right-click it in Visual Studio and select “Open in Blend”, this also works for opening a page from Blend in Visual Studio).

In the Behaviors section you’ll find a bunch of Actions and Behaviors. An interesting one here is the NavigateToPageAction, drag and drop that one onto the ListBox. You’ll notice that the Action has attached itself to the ListBox if you have a look at the Objects & Timeline pane.

Before we can navigate we need to create a new page, add a page called DetailPage.xaml to the View folder of the project. Creating the page can be done from either Blend or Visual Studio. After creating the DetailPage, go back to MainPage in Blend and select the NavigateToPageAction that’s attached to the Listbox in the Objects & Timeline pane. Go to the properties.

You’ll see here that the action contains a trigger. There we can select what event from the Listbox will trigger the action, set this to SelectionChanged. In the dropdown for TargetPage you should see MainPage and DetailPage (and any other pages you might have created), set it to DetailPage and run the app. Click on an item and you’ll see that the app navigates to the detailpage. This is what the action looks like in XAML.

Code Snippet
  1. <ListBox ItemTemplate="{StaticResource PersonTemplate}" ItemsSource="{Binding Persons}">
  2.     <i:Interaction.Triggers>
  3.         <i:EventTrigger EventName="SelectionChanged">
  4.             <ec:NavigateToPageAction TargetPage="/View/DetailPage.xaml" />
  5.         </i:EventTrigger>
  6.     </i:Interaction.Triggers>
  7. </ListBox>

Loading detailed data for clicked item

When we select an item we navigate to a detail page. It would be nice to effectively show all the details. When using a ListBox this is pretty easy. We can just define a property on the viewmodel and bind the ListBox’s SelectedItem property to the property on the viewmodel. The property could look something like this

Code Snippet
  1. public Person SelectedPerson
  2. {
  3.     get { return _selectedPerson; }
  4.     set
  5.     {
  6.         if (_selectedPerson == value) return;
  7.         _selectedPerson = value;
  8.         RaisePropertyChanged(() => SelectedPerson);
  9.         LoadDetails();
  10.     }
  11. }

The binding on the ListBox would look like this

Code Snippet
  1. <ListBox ItemTemplate="{StaticResource PersonTemplate}
  2.          ItemsSource="{Binding Persons}"
  3.          SelectedItem="{Binding SelectedPerson,
  4.                                 Mode=TwoWay}">

Notice that we have to specify that this is a two-way binding. If we don’t, the property will not get updated from the view. Databinding by default is OneWay, from the viewmodel to the view.

While this is a valid way of working, it has some issues.

  • LongListSelector doesn’t support binding to SelectedItem (I described workarounds for this here and here)
  • The DetailPage needs to have MainViewModel as datacontext, which is possible and allowed but often this means that a viewmodel turns into a superclass that handles the datacontext for every view.

On to the next possibility we go!

EventToCommand

The way of passing the selecteditem from the view to the viewmodel and to the next viewmodel I’m about to describe takes a bit more setup than the previous part. However, while it is a bit more work, it’s my preferred way of working. To me this feels like the “MVVM way” but use whatever feels most comfortable for you.

Go into Blend and delete the NavigateToPageAction that is still attached to the ListBox. Go back to the Assets pane, to the list of Behaviors. You’ll find that in the list is an EventToCommand behavior. This allows us to hook up events fired by controls in the view to trigger certain actions on the viewmodel. Drag & drop the EventToCommand onto the ListBox.

Before specifying the target command for the behavior, we’ll have to add one to the viewmodel first. Windows Phone has an interface called ICommand that we can use for binding. MVVM Light comes with two implementations of ICommand called RelayCommand and RelayCommand<T>. We’re going to use the generic version RelayCommand<T> because this way we can get the event arguments into our viewmodel.

Code Snippet
  1. private RelayCommand<SelectionChangedEventArgs> _selectionChangedCommand;
  2.  
  3. public RelayCommand<SelectionChangedEventArgs> SelectionChangedCommand
  4. {
  5.     get
  6.     {
  7.         return _selectionChangedCommand ??
  8.                (_selectionChangedCommand = new RelayCommand<SelectionChangedEventArgs>(OnSelectionChanged));
  9.     }
  10. }

When using the generic version of RelayCommand we specify the type of T as the type of eventargs we’re expecting. Note that this can also be a string that’s passed in as commandparameter for example when binding to a button’s command property.

SIDENOTE – the ?? operator: If you’ve never seen the ?? operator before, it checks if whatever’s on its leftside is not null, if it is it executes whatever’s on its rightside. In this case the rightside will only get executed the very first time the command is called, that’s when the private field is instantiated.

the parameter passed into the RelayCommand<T> constructor is the action that we’ll be executing when the command is called.

Code Snippet
  1. private void OnSelectionChanged(SelectionChangedEventArgs args)
  2. {
  3.     throw new System.NotImplementedException();
  4. }

We’ll complete this in a minute, just leave it like this to make the application compile.

Bind the EventToCommand Command property to the RelayCommand either through Blend or in XAML. Make sure to check the PassEventArgsToCommand checkbox when going via Blend. This is what the XAML should look like.

Code Snippet
  1. <ListBox ItemTemplate="{StaticResource PersonTemplate}"
  2.     ItemsSource="{Binding Persons}">
  3.     <i:Interaction.Triggers>
  4.         <i:EventTrigger EventName="SelectionChanged">
  5.             <Command:EventToCommand PassEventArgsToCommand="True" Command="{Binding SelectionChangedCommand, Mode=OneWay}"/>
  6.         </i:EventTrigger>
  7.     </i:Interaction.Triggers>
  8. </ListBox>

No more SelectedItem binding. If we place a breakpoint in the OnSelectionChanged method and check the parameter you should see the selected item in there.

So far, we’re using the controls their events, using a behavior to pass the eventhandler to a command on our ViewModel. No code behind required, clean MVVM setup. The next step is to navigate to another page and pass the selected item to another viewmodel. Let’s start by navigating.

Navigating via the ViewModel

I’ve mentioned before that navigating from within the viewmodel can be done by using a NavigationService. It’s time to do just that. A NavigationService is not included in Windows Phone so we’ll either need to write one or use an existing one. I’m going to do the latter and use an existing one.

Use either NuGet or the Package manager console to add the Cimbalino Windows Phone toolkit to the project

Install-Package Cimbalino.Phone.Toolkit

Now it’s time to revisit the ViewModelLocator. Remember SimpleIoc? We used the ViewModelLocator to register services and use constructor injection to inject those services into our viewmodels. First add a using statement to the ViewModelLocator

Code Snippet
  1. using Cimbalino.Phone.Toolkit.Services;

Next, register the NavigationService in SimpleIoc. (line 14)

Code Snippet
  1. public ViewModelLocator()
  2. {
  3.     ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  4.  
  5.     if (ViewModelBase.IsInDesignModeStatic)
  6.     {
  7.         // Create design time view services and models
  8.         SimpleIoc.Default.Register<IDataService, DesignDataService>();
  9.     }
  10.     else
  11.     {
  12.         // Create run time view services and models
  13.         SimpleIoc.Default.Register<IDataService, DataService>();
  14.         SimpleIoc.Default.Register<INavigationService, NavigationService>();
  15.     }
  16.  
  17.     SimpleIoc.Default.Register<MainViewModel>();
  18. }

Back to the MainViewModel, we add a new parameter to its constructor.

Code Snippet
  1. private INavigationService _navigationService;
  2. public MainViewModel(IDataService dataService, INavigationService navigationService)
  3. {
  4.      _navigationService = navigationService;

Using the NavigationService is pretty easy.

Code Snippet
  1. private void OnSelectionChanged(SelectionChangedEventArgs args)
  2. {
  3.     _navigationService.NavigateTo("/View/DetailPage.xaml");
  4. }

Do be careful with the path to the page, it’s a string so no intellisense. If the page is in a folder make sure to start with “/”. Run the app, click an item. The app should navigate to the DetailPage, just like we had before. Time to add the PersonViewModel. Add a class named PersonViewModel and make it inherit ViewModelBase, that’s enough for now.

Every new viewmodel in an MVVM Light application needs to be added to the ViewModelLocator. We need to register the viewmodel in SimpleIoc and create a property to allow databinding. First register the viewmodel in the ViewModelLocator’s constructor

Code Snippet
  1. SimpleIoc.Default.Register<PersonViewModel>();

Next is the property

Code Snippet
  1. public PersonViewModel Person
  2. {
  3.     get
  4.     {
  5.         return ServiceLocator.Current.GetInstance<PersonViewModel>();
  6.     }
  7. }

Now we can set the DetailPage’s datacontext to the PersonViewModel by adding this to the opening tag of the page.

Code Snippet
  1. DataContext="{Binding Person,
  2.                       Source={StaticResource Locator}}"

For your reference, here’s the complete tag

Code Snippet
  1. <phone:PhoneApplicationPage x:Class="MvvmDemo.View.DetailPage"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
  7. xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
  8. DataContext="{Binding Person,
  9.                       Source={StaticResource Locator}}"
  10. FontFamily="{StaticResource PhoneFontFamilyNormal}"
  11. FontSize="{StaticResource PhoneFontSizeNormal}"
  12. Foreground="{StaticResource PhoneForegroundBrush}"
  13. Orientation="Portrait"
  14. SupportedOrientations="Portrait"
  15. shell:SystemTray.IsVisible="True"
  16. mc:Ignorable="d">

Messaging

Now that we have two viewmodels, we need to setup a form of communication between them. Luckily for us, MVVM Light has something in place for this called the Messenger. The Messenger is a class that receives and delivers messages. One viewmodel subscribes for a certain message, the other viewmodel sends a message and the messenger makes sure it gets delivered nicely. The messenger can take any type and send it as a message, we could for example send an entire person, or the ID of a person and send it as an integer. But in a bigger app this could get complicated, imagine if 5 viewmodels start listening for integers but one is expecting the id of a product, another one expects the id of a person while a third one expects a result of some sorts. It would be a lot of work to get the subscribe / unsubscribe just right. That’s why I advice you to make it a habit to encapsulate the data in a special message class. Like for example to send our selected person over to the PersonViewModel.

Code Snippet
  1. public class PersonSelectedMessage : MessageBase
  2. {
  3.     public Person SelectedPerson { get; set; }
  4.     public PersonSelectedMessage(Person selectedPerson)
  5.     {
  6.         SelectedPerson = selectedPerson;
  7.     }
  8. }

As you can see, this is a really simple class with only one purpose: encapsulate a Person instance. The MessageBase baseclass is an MVVM Light class that contains some info about the sender and the target but I use this mainly to make the classes easier to recognize as MVVM Light messages. I also place all those message classes in a Messages folder in my project.

Let’s subscribe to this type of message from the PersonViewModel. First add a Person property to the PersonViewModel that we can bind to.

Code Snippet
  1. private Person _selectedPerson;
  2.  
  3. public Person SelectedPerson
  4. {
  5.     get { return _selectedPerson; }
  6.     set
  7.     {
  8.         if (_selectedPerson == value) return;
  9.  
  10.         _selectedPerson = value;
  11.         RaisePropertyChanged(() => SelectedPerson);
  12.     }
  13. }

Then add this in the PersonViewModel constructor.

Code Snippet
  1. public PersonViewModel()
  2. {
  3.     Messenger.Default.Register<PersonSelectedMessage>(this, msg =>
  4.     {
  5.         SelectedPerson = msg.SelectedPerson;
  6.     });
  7. }

This registers our current instance of PersonViewModel to receive messages of the PersonSelectedMessage type. We will send this message from the MainViewModel in the OnSelectionChanged method that fires when selecting a person in the ListBox.

Code Snippet
  1. private void OnSelectionChanged(SelectionChangedEventArgs args)
  2. {
  3.     _navigationService.NavigateTo("/View/DetailPage.xaml");
  4.     Messenger.Default.Send(new PersonSelectedMessage(args.AddedItems[0] as Person));
  5. }

If you set a breakpoint in the action that fires when a message arrives and try to select a person the first time it will probably fail. This is because the message departs before the PersonViewModel has had a chance to initialize and register for the message, it will be sent but it will never arrive. If you hit the back key back to the MainPage and select another person it will arrive because the PersonViewModel instance already exists and is listening to the message. The quickest (and easiest) way to fix this is to make sure that PersonViewModel is initialized when the app launches. We can use an overload of SimpleIoc’s register method for this.

In the ViewModelLocator, add true as a parameter to the registration

Code Snippet
  1. SimpleIoc.Default.Register<PersonViewModel>(true);

This will initialize the class at the moment of registration and it will register itself as a subscriber for the PersonSelectedMessage. After binding the page title to SelectedPerson.Name and running the app this is the result:

If this was a real application you would use the action of the messenger to fetch the detailed information of the selected item. DataBinding takes care of displaying the data on screen.

Conclusion

In this second part of my practical guide to MVVM Light I’ve discusses the way I usually work to select an item from a list, navigate to a detail page and fetch / show detailed information.

Some more MVVM related articles:

Some more in depth IOC/DI articles:

Feel free to ping me on Twitter (@NicoVermeir) should you have any questions.

The code for this second part can be found on OneDrive.


Tags:

.Net | Binding | MVVM Light | Metro | Silverlight | WP7 | WP8 | WPF | WinRT | Windows 8 | XAML

Win Store: SuspensionManager failed

by Nico

While implementing tombstoning in a Windows Store app I recently ran into this issue. Some pages tombstoned and resumed perfectly, while some other pages gave this error when tombstoning

This one took me a while to figure out, but I finally found the problem. But before diving into the solution, I’ll show you how I got to this error.

Tombstoning

If you’re reading this, I’m assuming you know about the app lifecycle and tombstoning so I’m not going to explain that. To demonstrate the problem I created a blank app, added in a basic page so that Visual Studio included the NavigationHelper and SuspensionManager classes.

In the app I have two pages, Mainpage.xaml and Page2.xaml. Mainpage has a button that takes me to Page2. The navigation happens with the build-in NavigateToPageAction, easily dragged and dropped onto the button from Blend.

This creates an EventTriggerBehavior on the button that triggers a NavigateToPageAction

All that’s left to do is set the target page in the NavigateToPageAction properties

And we’re done. We’ve just created an app with a button that navigates to another page without writing any code, pretty neat and easy stuff right?

Next thing I did was follow this MSDN article that shows in a few easy steps how to implement tombstoning so that if the app tombstones on a certain page and the user switches back to the app, it reloads that page. It worked and all was well. That is, until I implemented the tombstoning on a page that was navigated to using the NavigateToPageAction. tombstoning that page always resulted in the error shown in the screenshot at the beginning of this post (and it took me a few hours to discover that the action was at fault here). Let’s have a closer look to see what’s actually happening here.

Navigation and NavigationParameters

When navigating between pages we can pass parameters. In Windows Store the signature of the Frame.Navigate function is this

Navigate(Type)
Navigate(Type, Object)
Navigate(Type, Object, NavigationTransitionInfo)

The parameter is of type Object, meaning we can pass in anything we’d like. Pretty powerful right? Right, except when tombstoning.

At a certain point in the Tombstoning process this snippet of code gets executed

Code Snippet
  1. private static void SaveFrameNavigationState(Frame frame)
  2. {
  3.     var frameState = SessionStateForFrame(frame);
  4.     frameState["Navigation"] = frame.GetNavigationState();
  5. }

This will save the current NavigationState of the pages into a dictionary. The caveat here is that this only works with primitive types. If we pass strings or integers as parameter this will work, no problem. If we pass in an object of type MyClass we will get the SuspensionManager failed error.

Okay cool, that’s all great, we found a possible source of the error. But, we’re not passing in any parameters to the page, so why are we getting the error? Let’s set a breakpoint in the OnNavigatedTo method in Page2.xaml.cs

Well well, would you look at that. Our NavigateToPageAction snuck in a little parameter without telling us, and that parameter is not a primitive type so we get a crash.

The fix + conclusion

The fix is actually really easy, don’t use NavigateToPageAction. Yes just don’t use it. I know it’s really fast and easy but it breaks the entire tombstoning thingy. I fixed it by calling Frame.Navigate (Type) from the button’s click event.

I’ve uploaded a sample with two buttons on my OneDrive, one button has the crashing effect, the other one doesn’t.

Download Link


Tags:

.Net | Windows 8 | WinRT | XAML | tombstoning | lifecycle

A custom button that disappears in snapped mode

by Nico

I’m currently working on a Windows 8.1 app that has quite some buttons in the app bar. The buttons are not positioned next to each other in one row and are not all the same size. This means that I can’t use the new CommandBar to auto-hide some buttons whenever the app gets snapped to the side. That means that it’s time for a custom button.

Actually, I have two solutions to this problem. One that puts the hide/show functionality in the button and one that puts it in the page where you use the appbar.

The one with functionality in the button

Create a new class and let it derive from Button.

Code Snippet
  1. public class CustomAppBarButton : Button
  2. {
  3.     public static readonly DependencyProperty HideOnSnapProperty = DependencyProperty.Register(
  4.         "HideOnSnap", typeof (bool), typeof (CustomAppBarButton), new PropertyMetadata(default(bool)));
  5.  
  6.     public bool HideOnSnap
  7.     {
  8.         get { return (bool) GetValue(HideOnSnapProperty); }
  9.         set { SetValue(HideOnSnapProperty, value); }
  10.     }
  11.  
  12.     public CustomAppBarButton()
  13.     {
  14.         HideOnSnap = false;
  15.  
  16.         Window.Current.SizeChanged += CurrentOnSizeChanged;
  17.     }
  18.  
  19.     private void CurrentOnSizeChanged(object sender, WindowSizeChangedEventArgs windowSizeChangedEventArgs)
  20.     {
  21.         if (!HideOnSnap)
  22.             return;
  23.  
  24.         var size = Window.Current.Bounds;
  25.  
  26.         if (size.Width <= size.Height)
  27.         {
  28.             Visibility = Visibility.Collapsed;
  29.         }
  30.         else
  31.         {
  32.             Visibility = Visibility.Visible;
  33.         }
  34.     }
  35. }

First thing we need is a dependency property so we can specify whether or not we want to hide a button in snapped view. From the constructor we subscribe to the SizeChanged event of the current window. Whenever that event fires every button will check if it needs to hide. If HideOnSnap is enabled, the buttons will check if the app is currently snapped by checking if the width of the window is smaller than the height.

To use this control, and let the button hide on snap you can use something like this

Code Snippet
  1. <local:CustomAppBarButtonType1 Content="Button1" HideOnSnap="False" />
  2. <local:CustomAppBarButtonType1 Content="Button2" HideOnSnap="True" />

This works peachy, but if you have an appbar with multiple of these buttons and run on a slower system you might experience some delay when opening up the appbar for the first time. All buttons are getting created and are attaching the event handler so depending on the amount of buttons it might take some time.

If you experience the delay, option 2 might work better

The one where the page handles it

This option also needs a custom button class but it’s a much smaller one

Code Snippet
  1. public class CustomAppBarButton : Button
  2. {
  3.     public static readonly DependencyProperty HideOnSnapProperty = DependencyProperty.Register(
  4.         "HideOnSnap", typeof (bool), typeof (CustomAppBarButton), new PropertyMetadata(default(bool)));
  5.  
  6.     public bool HideOnSnap
  7.     {
  8.         get { return (bool) GetValue(HideOnSnapProperty); }
  9.         set { SetValue(HideOnSnapProperty, value); }
  10.     }
  11.  
  12.     public CustomAppBarButton()
  13.     {
  14.         HideOnSnap = false;
  15.     }
  16. }

No event handling in this class, just a dependency property to specify whether or not it needs to hide. The actual hiding and showing of the buttons happens in the page itself.

Code Snippet
  1. public MainPage()
  2. {
  3.     InitializeComponent();
  4.     SizeChanged += OnSizeChanged;
  5. }
  6.  
  7. private async void OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
  8. {
  9.     var size = Window.Current.Bounds;
  10.     var dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
  11.  
  12.     if (size.Width <= size.Height)
  13.     {
  14.         await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, HideAllHideableButtons);
  15.     }
  16.     else
  17.     {
  18.         await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, ShowAllHideableButtons);
  19.     }
  20. }

We register for the SizeChanged event of the page (event comes from the FrameworkElement class, a page in Windows 8.1 derives from that class). The rest of the code is very similar from the code in the buttons. A difference is that we need to use the dispatcher here to marshall the hiding / showing of the buttons to the UI thread.

Here’s the code to hide all hideable buttons (note that you have to name your appbar, mine is called AppBarBottom

Code Snippet
  1. private void HideAllHideableButtons()
  2. {
  3.     var buttons = AppBarBottom.FindDescendantsByType<CustomAppBarButtonType2>().Where(b => b.HideOnSnap);
  4.  
  5.     foreach (var appBarButton in buttons)
  6.     {
  7.         appBarButton.Visibility = Visibility.Collapsed;
  8.     }
  9. }

We’re looking for all controls on the page that are of type CustomAppBarButton and that have HideOnSnap set to true (don’t worry about the FindDescendantsByType function, that’s an extension method, I’ll come back to it in a minute).

Every button that we found, we set to collapsed and voila, buttons are hidden when snapped. Getting them to show up again is very (very) similar

Code Snippet
  1. private void ShowAllHideableButtons()
  2. {
  3.     var buttons = this.FindDescendantsByType<CustomAppBarButton>().Where(b => b.HideOnSnap);
  4.  
  5.     foreach (var appBarButton in buttons)
  6.     {
  7.         appBarButton.Visibility = Visibility.Visible;
  8.     }
  9. }

As for the FindDescendantsByType<T> extension method:

Code Snippet
  1. public static IEnumerable<T> FindDescendantsByType<T>(this DependencyObject depObj) where T : DependencyObject
  2. {
  3.     if (depObj != null)
  4.     {
  5.         for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
  6.         {
  7.             DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
  8.             if (child != null && child is T)
  9.             {
  10.                 yield return (T)child;
  11.             }
  12.  
  13.             foreach (T childOfChild in FindDescendantsByType<T>(child))
  14.             {
  15.                 yield return childOfChild;
  16.             }
  17.         }
  18.     }
  19. }

this will look through the visual tree in search for elements of the specified type (I think I found this method on SO somewhere, forgot the exact link but this is not my code).

Usage is exactly the same as with the first type of button.

Code Snippet
  1. <local:CustomAppBarButtonType2 Content="Button1" HideOnSnap="False" />
  2. <local:CustomAppBarButtonType2 Content="Button2" HideOnSnap="True" />

Conclusion

In this post I’ve discussed two ways of creating a custom button that can hide itself when the application gets snapped to the side, allowing for a quick way to create an adaptable application bar.

You can find a demo application using both ways of working on my OneDrive (Top appbar uses first type, bottom appbar uses second type).


Tags:

.Net | WinRT | Windows 8 | XAML

Branching XAML Styler

by Nico

Some time ago I blogged about having recompiled the great XAML Styler plugin so it would install into Visual Studio 2013. The recompiled plugin suddenly became an unexpected success and it got me thinking that this plugin should really continue to exist, even if the original author isn’t supporting it anymore (not sure of this but it has been quite some time since he pushed anything to Codeplex).

After waiting around a bit I’ve decided to download the original source code, get it up and running in Visual Studio 2013 and push it to both Github and the Visual Studio gallery. So I’m happy to announce that the code can be found at Github and the VS2013 version of the plugin can be found at the Visual Studio Gallery

The future?

The version that is now on the gallery is the exact same version that I’ve compiled back in November. It’s the plugin that the original author created but recompiled with the VS2013 SDK. I did create a new VS Package project to be able to have it on the gallery side by side with the original plugin.

As for the future of the project, I’m currently going through the source code, getting to know the application and the code that makes it tick. Afterwards I’m planning on having a look at the logged issues on the original Codeplex site and tackle those.

Issues

Should you run into any issues while using the forked plugin please log an issue on the Github page.

Contributions

So you want to contribute? Great! Fork the Github version and go wild! Create a Pull request when you’re ready and if everything checks out I’ll happily merge your changes into the main branch and give props to every contribution you make.

Let’s keep this plugin alive and make it even better together!


Tags:

.Net | Community | Patterns | Silverlight | WP7 | WP8 | WPF | WinRT | Windows 8 | XAML | github | OSS

Data validation in Windows Phone 8

by Nico

Whenever you need to do data input you’re probably going to add some form of data validation. There is a ton of information out there on how to do this in Silverlight and WPF but information on Windows Phone 8 is rather hard to find. After doing some research on the topic I’ve landed on the Fluent Validation library available on Nuget and decided to write something on the subject myself. I’ve put together a quick sample, including integration with SimpleIoc in MVVM Light.

Adding the package

We start of with an empty solution, add the MVVM Light libraries to it, bind the datacontext of MainPage to MainViewModel as you would usually do. Once the MVVM setup is complete it’s time to add the Fluent Validation package to the project.

Install-Package FluentValidation

Fluent Validation is an open source project available on Codeplex

Fluent Validation has libraries for

  • .net 4.0
  • MVC 3
  • MVC 4
  • MVC 5
  • Portable

The settings of the portable class library are

Meaning that the implementation I’m about to show will work just as well on Windows Store apps, so +1 for code sharing!

Creating the Model

The demo app is a simple registration form, a new user will be able to enter his name, birthdate and country. We’ll build validation rules on those properties later on. We’ll only have one model class in this app, called Member.

Code Snippet
  1. public class Member
  2. {
  3.     public string Name { get; set; }
  4.     public DateTime BirthDate { get; set; }
  5.     public string Country { get; set; }
  6. }

Setting up the validation

There is some work involved in getting everything setup, don’t worry, it’s hardly rocket science.

We’re going to create a ValidaterFactory. We need this because we’re going to use SimpleIoc to inject the validators into the ViewModels. If you don’t want to do this you can just create the validators and instantiate them whenever you need one, the Codeplex page of Fluent Validation has great documentation on this.

A ValidatorFactory inherits from the ValidatorFactoryBase class included in the library

Code Snippet
  1. public class ValidatorFactory : ValidatorFactoryBase
  2. {
  3.     public ValidatorFactory()
  4.     {
  5.         //register the Validators
  6.         SimpleIoc.Default.Register<IValidator<Member>, MemberValidator>();
  7.     }
  8.  
  9.     public override IValidator CreateInstance(Type validatorType)
  10.     {
  11.         return SimpleIoc.Default.GetInstance(validatorType) as IValidator;
  12.     }
  13. }

The constructor of the ValidatorFactory is where I’m registering all validators. You could do this in the ViewModelLocator as well, like any other class / repository / viewmodel but this keeps my VMLocator cleaner and keeps the validation logic a bit closer together.

The CreateInstance function needs to be overridden and returns the instance of the requested validator.

Building a validator

Almost there, in this step we’re building a validator for the Member class. A validator inherits from AbstractValidator<T> where T is the class you want to validate.

Code Snippet
  1. public class MemberValidator : AbstractValidator<Member>
  2. {
  3.     public MemberValidator()
  4.     {
  5.         RuleFor(member => member.Name).NotEmpty();
  6.         RuleFor(member => member.BirthDate).LessThan(DateTime.Today);
  7.     }
  8. }

In the constructor of the validator we can finally start to add some rules. In this case we’re saying that the Name property should not be empty and that the birthdate property should be before today’s date.

We’ll need to register this class into our IOC, so in ViewModelLocator add this line

Code Snippet
  1. SimpleIoc.Default.Register<ValidatorFactory>(true);

We pass in ‘true’ as parameter to make sure the object is instantiated at the moment of registration, that way all validators are registered in the IOC as well (as seen in the ValidatorFactory’s constructor).

As a reference, these are all the built in validators of Fluent Validation

  • NotNull
  • NotEmpty
  • NotEqual
  • Equal
  • Length
  • LessThan
  • LessThanOrEqual
  • GreaterThan
  • GreaterThanOrEqual
  • Predicate
  • RegEx
  • Email

Quite an impressive list, and probably most of what you’ll need. Just in case that the one that you need isn’t included, you can build your own, we’ll discuss that in a bit. Let’s get these rules to work first.

Validating data

So we have a factory, we have a validator, all are getting registered in our IOC, time to hook up the ViewModels and getting some validation done.

In the MainViewModel we add a property of type Member that we’ll bind against

Code Snippet
  1. private Member _newMember;
  2. public Member NewMember
  3. {
  4.     get { return _newMember; }
  5.     set
  6.     {
  7.         if (_newMember == value) return;
  8.  
  9.         _newMember = value;
  10.  
  11.         RaisePropertyChanged(() => NewMember);
  12.     }
  13. }

Next, we’ll add two fields, one for the validator and one for the save command

Code Snippet
  1. private ICommand _saveMemberCommand;
  2. private IValidator<Member> _validator;

Next up is the ICommand property for the Save Command

Code Snippet
  1. public ICommand SaveMemberCommand
  2. {
  3.     get { return _saveMemberCommand ?? (_saveMemberCommand = new RelayCommand(SaveMember)); }
  4. }

Before we dive into the SaveMember method, we’ll need to do some constructor injection and initialization.

Code Snippet
  1. public MainViewModel(ValidatorFactory validator)
  2. {
  3.     NewMember = new Member
  4.     {
  5.         BirthDate = DateTime.Today
  6.     };
  7.  
  8.     _validator = validator.GetValidator<Member>();
  9. }

As a parameter we get our ValidatorFactory, using its GetValidator<T> function we can fill up the _validator field. NewMember gets instantiated and the BirthDate property is set to a default of today.

And last but not least, the SaveMember method

Code Snippet
  1. private void SaveMember()
  2. {
  3.     if (IsValid())
  4.     {
  5.         MessageBox.Show("Registration completed!");
  6.     }
  7. }
  8.  
  9. private bool IsValid()
  10. {
  11.     ValidationResult validationResult = _validator.Validate(NewMember);
  12.  
  13.     if (!validationResult.IsValid)
  14.     {
  15.         ShowErrors(validationResult.Errors);
  16.  
  17.         return false;
  18.     }
  19.  
  20.     return true;
  21. }
  22.  
  23. private void ShowErrors(IEnumerable<ValidationFailure> errors)
  24. {
  25.     StringBuilder builder = new StringBuilder();
  26.  
  27.     builder.AppendLine("The following errors occured:");
  28.     foreach (ValidationFailure error in errors)
  29.     {
  30.         builder.AppendLine("- " + error.ErrorMessage);
  31.     }
  32.  
  33.     MessageBox.Show(builder.ToString(), "error", MessageBoxButton.OK);
  34. }

To validate an instance we call the Validate function on a validator for that type, in this case ‘Member’. That function returns a ValidationResult. ValidationResult contains a bool property IsValid and a list of errors that it found.

We iterate over this list and put every error into a StringBuilder to get a nice error message in a messagebox. If I try to save with an empty name and today’s date as birthdate I get this.

Our validation is working! But those messages could be a bit better. Fluent Validator provides us with options to adjust the property name or the entire message. Change the constructor of the MemberValidator to this

Code Snippet
  1. public MemberValidator()
  2. {
  3.     RuleFor(member => member.Name).NotEmpty().WithMessage("You should enter your name");
  4.     RuleFor(member => member.BirthDate).LessThan(DateTime.Today).WithName("date of birth");
  5. }

On line 3 we use .WithMessage(“”) to replace the default message by whatever we want. Line 4 replaces the default name of the property, the result is similar yet slightly different

Adding a custom validator

Let’s say that we want to add validation to the Country property. This property must have a value of either ‘Belgium’, ‘Netherlands’ or ‘Luxemburg’ (this is called the BeNeLux). Obviously, this isn’t included as one simple validator so we’ll just build it ourselves.

We’ll need a class that inherits from PropertyValidator and overrides the IsValid function.

Code Snippet
  1. public class CountryMustBeInBenelux : PropertyValidator
  2. {
  3.     public CountryMustBeInBenelux()
  4.         : base("{PropertyName} is not a Benelux country")
  5.     {
  6.  
  7.     }
  8.  
  9.     protected override bool IsValid(PropertyValidatorContext context)
  10.     {
  11.         if (context.PropertyValue == null)
  12.             return false;
  13.  
  14.         string country = context.PropertyValue.ToString().ToLower();
  15.  
  16.         return country == "belgium" || country == "netherlands" || country == "luxemburg";
  17.     }
  18. }

The string that we pass in to the base constructor is the default message that will be used for this validator. The IsValid function takes a parameter of PropertyValidatorContext. This will contain the property that we want to validate and its value.

Next, in the MemberValidator constructor we add the validation for the Country property

Code Snippet
  1. public MemberValidator()
  2. {
  3.     RuleFor(member => member.Name).NotEmpty().WithMessage("You should enter your name");
  4.     RuleFor(member => member.BirthDate).LessThan(DateTime.Today).WithName("date of birth");
  5.  
  6.     RuleFor(member => member.Country).SetValidator(new CountryMustBeInBenelux());
  7. }

As you can see we need to use the SetValidator function to add our own validator.

The result now is this (I’ve entered a name and a valid birthdate to clean up the error list a bit)

 

Conclusion

In this article I’ve discussed the use of Fluent Validator to do data validation in Windows Phone 8 apps. I’ve used the portable version of the library so these examples should work just fine on Windows 8 as well.

The Fluent Validator library has many more options than what I’ve discussed here and they are all well documented, head over the the Codeplex page if you want to do more and deeper validation.

The sample project can be found on my SkyDrive


Tags:

.Net | Data | Validation | Fluent | MVVM Light | NuGet | WP8 | Windows 8 | WinRT | XAML

Xaml Styler for Visual Studio 2013

by Nico

Xaml Styler is a free Visual Studio 2012 extension available from the gallery. I’ve been using this extension for quite some time now and I’m really happy with how it styles my XAML code. Unfortunately the extension isn’t compatible with Visual Studio 2013.

Luckily for us, the extension is on Codeplex. I’ve downloaded the code, referenced the new Visual Studio SDK and recompiled it. It seems to be working fine with Visual Studio 2013 now.

I’ve uploaded the binaries to my Skydrive folder so that everyone can enjoy the extension in Visual Studio 2013 until the original author of the plug-in creates official Visual Studio 2013 support.

Be aware, this version isn’t thoroughly tested by anyone! I’ve compiled it, installed it and I’m currently using it. I haven’t ran into any problems yet but that doesn’t mean that it won’t have any problems. These binaries are supplied as-is.

Download from Skydrive

Gallery link

Original Codeplex page


Tags:

.Net | WP7 | WP8 | WPF | WinRT | Windows 8 | XAML

Launching a Win8 app from WP8 with Azure custom API

by Nico

Imagine you have an app where people can browse through all sorts of data, let’s take Wikipedia for example. You find an interesting article on the Wikipedia app on your Windows Phone device. A phone screen is (usually) pretty small so it would be nice if we could just send that article to our pc where a toast pops up, when the toast is clicked the Wikipedia app on Windows 8 opens up on that same article. A nice experience for the user, added value for our apps and not too hard to do.

The Service

As the title of this post mentiones, we’re going to use Windows Azure Mobile Services for this. A while ago Microsoft launched the custom API option in Mobile Services (WAMS for short) and those custom APIs are just what we need.

The server side of WAMS uses Node.js so that means:

We’ll start by creating a new Mobile Service (if you don’t know how, follow this tutorial to the point where they’re creating a new app, we’ll create the app manually).

Once the mobile service is created, navigate to the API tab and add a new API. Gave it a name and leave the permissions default. The end result should look like this.

Click the arrow icon next to the API name to start editing the script. The script looks like this by default.

Code Snippet
  1. exports.post = function (request, response) {
  2.     // Use "request.service" to access features of your mobile service, e.g.:
  3.     //   var tables = request.service.tables;
  4.     //   var push = request.service.push;
  5.  
  6.     response.send(statusCodes.OK, { message: 'Hello World!' });
  7. };
  8.  
  9. exports.get = function (request, response) {
  10.     response.send(statusCodes.OK, { message: 'Hello World!' });
  11. };

There are options here both for POST and GET methods, implemented with Hello World stuff. We’ll only be needing the POST part, the GET method we’ll just leave alone.

This is the new POST method:

Code Snippet
  1. exports.post = function (request, response) {
  2.     process.env.WNS_CLIENT_ID = 'YOUR_CLIENT_ID_HERE';
  3.     process.env.WNS_CLIENT_SECRET = 'YOUR_CLIENT_SECRET_HERE';
  4.  
  5.     var wns = request.service.push.wns;
  6.     var message = request.body.message;
  7.     var title = request.body.title;
  8.     var launchParam = request.body.launchParam;
  9.     var channel = request.body.channel;
  10.  
  11.     wns.sendToastText02(channel, {
  12.         text1: title,
  13.         text2: message
  14.     },
  15.          {
  16.              launch: launchParam,
  17.              success: function () {
  18.                  response.send(statusCodes.OK, { isSuccess: true, response: statusCodes.OK });
  19.              },
  20.              error: function () {
  21.                  response.send(statusCodes.OK, { isSuccess: false, response: statusCodes.NOK });
  22.              }
  23.          }
  24.          );
  25.  
  26. };

You’ll notice on line two and three that you’ll need to insert your own client ID and client secret. To get those we’ll need to create a new app on the Windows Store developer site.

Give an app name to the new app, save it and open the Services option.

On the services page, click on “Live Services Site”, on that site select “Authenticating your Service” and take note of the Client ID and Client Secret.

Usually, when using push notifications from a WAMS we can add those two keys into the management portal on Azure. However, when using a Custom API the WNS (Windows Notification Service) doesn’t seem to know that they are there. That’s the reason we’re including them into the script code here on lines two and three.

Last step here is to create a new Windows Store application in Visual Studio, Right-click the project, select Store and associate it with the app we’ve just created on the Windows Developer portal.

We now have an application hooked up to a registered application on the Windows Developer portal with access to WNS through the client ID and secret.

Let’s have a look at the rest of the script.

Code Snippet
  1. var wns = request.service.push.wns;
  2. var message = request.body.message;
  3. var title = request.body.title;
  4. var launchParam = request.body.launchParam;
  5. var channel = request.body.channel;

In the build-in API of WAMS we have access to an object called push. Push has a reference to WNS and can call push notifications. In a custom API we can find the Push object in request.service. Message and Title will be the content of the toast, channel is the channel used to send the toast from the server to the client and launchParam is what will determine the page we navigate to when the toast is clicked. All these parameters will be send over the wire from the Windows Phone app.

Code Snippet
  1. wns.sendToastText02(channel, {
  2.     text1: title,
  3.     text2: message
  4. },
  5.      {
  6.          launch: launchParam,
  7.          success: function () {
  8.              response.send(statusCodes.OK, { isSuccess: true, response: statusCodes.OK });
  9.          },
  10.          error: function () {
  11.              response.send(statusCodes.OK, { isSuccess: false, response: statusCodes.NOK });
  12.          }
  13.      }
  14.      );

This piece of the script will do the actual sending of the push notification. We call the sendToastText02 method on the wns object (for an overview of all the possibilities of wns, have a look at MSDN). The parameters for the method are simple, first it needs the channel. The channel is a direct link between an installation of your app and the server. It’s unique for every installation of the app. Next parameter is the payload of the toast, the information that will be shown on the toast message itself. Third parameter are the options. This is where we pass the launch parameters for the Windows app and the functions for success and error.

That’s all for the script. Pretty easy right?

Windows Phone app

The Windows Phone app is pretty straightforward as well. In this proof of concept it’ll just be an app with a bunch of buttons, when the Windows 8 app starts it will show the button that was clicked on the phone. Create a new Windows Phone 8.0 application and add the following NuGet package to the project.

Install-Package WindowsAzure.MobileServices

This will install the WAMS SDK into the project. We’ll need this SDK to fetch the channel and request the toast message.

The Windows Phone app only has one page with a really simple layout

Code Snippet
  1. <!--  ContentPanel - place additional content here  -->
  2. <StackPanel x:Name="ContentPanel"
  3.             Grid.Row="1"
  4.             Margin="12,0,12,0">
  5.     <TextBlock Text="Enter ID" />
  6.     <TextBox x:Name="TextBoxId" />
  7.     <Button Click="Button_Click" Content="Button 1" />
  8.     <Button Click="Button_Click" Content="Button 2" />
  9.     <Button Click="Button_Click" Content="Button 3" />
  10.     <Button Click="Button_Click" Content="Button 4" />
  11.     <Button Click="Button_Click" Content="Button 5" />
  12.     <Button Click="Button_Click" Content="Button 6" />
  13.     <Button Click="Button_Click" Content="Button 7" />
  14.     <Button Click="Button_Click" Content="Button 8" />
  15. </StackPanel>

A Textbox that will hold an ID and 8 buttons that use the same click event handler. The Windows 8 app that we’ll build in a minute will request a Channel from WNS, we’ll save that channel into our WAMS database. The ID that we enter here in the textbox is the ID of the record that holds the channel that we want to use. That means that in a real app, you’ll need to find a way to get the ID from the Windows 8 app into the Windows Phone app. Possibilities here are NFC or QR codes, or just plain text. Alternatively, you could use the username from a Microsoft Account to store and retrieve the channel instead of an ID.

Next we need to initialize the WAMS SDK in App.xaml.cs

Code Snippet
  1. public partial class App : Application
  2. {
  3.      public static MobileServiceClient MobileService = new MobileServiceClient(
  4.             "https://nicopushdemo.azure-mobile.net/",
  5.             "qCWCpYmWlJiOyXFQnKscFYnNixruku41"
  6.         );

You’ll need the values of your own service here of course. It can be found by going to the Azure management portal, selecting your WAMS and opening the “Connecting an existing application” option.

Here’s the button event handler for the eight buttons

Code Snippet
  1. private async void Button_Click(object sender, RoutedEventArgs e)
  2. {
  3.     Notification notification = new Notification();
  4.  
  5.     notification.Channel = await FetchChannel(int.Parse(TextBoxId.Text));
  6.     notification.Message = "Click to launch the app";
  7.     notification.Title = "Message from the Phone app!";
  8.     notification.LaunchParam = ((Button) sender).Content.ToString();
  9.  
  10.     var response = await App.MobileService.InvokeApiAsync<Notification, NotificationResult>("notifications", notification);
  11.  
  12.     if (response.IsSuccess)
  13.     {
  14.         MessageBox.Show("Toast succes!");
  15.     }
  16. }
  17.  
  18. private async Task<string> FetchChannel(int id)
  19. {
  20.     var channels = await App.MobileService.GetTable<Channel>().Where(c => c.Id == id).ToListAsync();
  21.  
  22.     return channels[0].ChannelUri;
  23. }

When one of the buttons is clicked an instance of Notification is created, Notification is a class that we build ourselves, looks like this

Code Snippet
  1. public class Notification
  2. {
  3.     [JsonProperty(propertyName: "message")]
  4.     public string Message { get; set; }
  5.  
  6.     [JsonProperty(propertyName: "title")]
  7.     public string Title { get; set; }
  8.  
  9.     [JsonProperty(propertyName: "channel")]
  10.     public string Channel { get; set; }
  11.  
  12.     [JsonProperty(propertyName: "launchParam")]
  13.     public string LaunchParam { get; set; }
  14. }

FetchChannel will use the entered ID to fetch the channel from the WAMS database (saving the channel in the DB will be done from the Windows Store app). The LaunchParam is the content from the button that was clicked.

Once the Notification instance is filled up, we call the custom API by calling InvokeAPIAsync, the generic types passed in are the type of the parameter and the type of the expected result. The expected result is NotificationResult

Code Snippet
  1. public class NotificationResult
  2. {
  3.     [JsonProperty(PropertyName = "isSuccess")]
  4.     public bool IsSuccess { get; set; }
  5.  
  6.     [JsonProperty(PropertyName = "response")]
  7.     public string Response { get; set; }
  8. }

The parameters for InvokeApiAsync are the name of the custom API, the object of the same type that was specified. The WAMS SDK will take care of deserializing that object into a JSON format using Json.NET before sending it over the wire to our API.

Windows 8 app

The final piece of the puzzle is the Windows 8 app. This is a very basic app consisting of two pages. An empty MainPage and a SecondPage. This to prove that you can navigate to any page when launched from a toast.

Create an empty Windows 8 app and once again add the WAMS SDK through NuGet.

Install-Package WindowsAzure.MobileServices

We’ll start by initializing the WAMS SDK in App.xaml.cs

Code Snippet
  1. sealed partial class App : Application
  2. {
  3.      public static PushNotificationChannel CurrentChannel { get; private set; }
  4.  
  5.      public static MobileServiceClient MobileService = new MobileServiceClient(
  6.              "https://nicopushdemo.azure-mobile.net/",
  7.              "qCWCpYmWlJiOyXFQnKscFYnNixruku41"
  8.          );
  9.  
  10.      private async void AcquirePushChannel()
  11.      {
  12.          CurrentChannel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
  13.          var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
  14.  
  15.          if(settings.Values.ContainsKey("channel"))
  16.          {
  17.              string previousChannel = settings.Values["channel"].ToString();
  18.  
  19.              if(previousChannel == CurrentChannel.Uri)
  20.                  return;
  21.          }
  22.  
  23.          settings.Values["channel"] = CurrentChannel.Uri;
  24.  
  25.          await MobileService.GetTable<Channel>().InsertAsync(new Channel{ChannelUri = CurrentChannel.Uri});
  26.      }

A bit more initial work needed here. First the same codeblock as the one in the WP8 app. Next is the AcquirePushChannel method. This one will ask WNS for a push channel, save it to the WAMS DB and into the Application’s settings. This is because a channel has a lifetime, during this time the application will be able to reuse that same channel. On every app start we’ll check if the channel we receive from WNS is the same one that is stored in the WAMS DB, if it isn’t we store it again.

Now, the magic also happens here in App.xaml.cs, at the end of the OnLaunched method.

Code Snippet
  1. string launchArgs = e.Arguments.Trim().ToString();
  2. if (launchArgs != string.Empty)
  3. {
  4.     rootFrame.Navigate(typeof(SecondPage), launchArgs);
  5. }
  6.  
  7. // Ensure the current window is active
  8. Window.Current.Activate();

We’ll check to see if the LaunchActivedArgs have some arguments. If they don’t, nothing special happens and MainPage is loaded. If they do, the argument will be the LaunchParams we’ve passed from the WP8 app, to the custom API. That value has now finally reached our Windows 8 app via the toast. We navigate to SecondPage and pass in the launchArgs as parameter.

SecondPage.xaml looks like this

Code Snippet
  1. <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  2.     <TextBlock x:Name="SelectedItem" Style="{StaticResource HeaderTextBlockStyle}" />
  3. </Grid>

In the code behind of SecondPage we’ll need to override OnNavigatedTo

Code Snippet
  1. protected override void OnNavigatedTo(NavigationEventArgs e)
  2. {
  3.     SelectedItem.Text = "Navigated to this page by clicking in the phone app on " + e.Parameter;
  4.     base.OnNavigatedTo(e);
  5. }

And that’s basically it.

Making it happen

Run the Windows 8 app once, so that it’s installed on your system and a channel is registered and saved into the WAMS DB. Feel free to close the app afterwards.

Launch the Windows Phone app, insert the correct ID into the textbox and hit any of the buttons.

Click the toast when it pops up and be amazed by the result Glimlach

Conclusion

In this post I’ve talked about a way to share data between apps through the use of push notifications. When you have the same app on both Windows Phone and Windows 8 this provides a cool way for your user to switch platforms while remaining on the same part of the app.

Download the projects from my SkyDrive:


Tags:

.Net | Azure | Devices | NuGet | WP8 | WinRT | Windows 8 | XAML

Porting a real win8 app to WP8–part 3

by Nico

It’s been a good while since I last worked on porting Comic Cloud from Windows 8 to Windows Phone. If you can still remember, the goal was to maximize code reuse by using PCL wherever possible.

Part 3 will be the last part in this series, I’m currently holding a fully functional Windows Store app and a Windows Phone 8 app that can navigate pages and sent a search query to the api using a shared service layer. Theoretically everything is shared between the two platforms except the views, which makes sense. But it still required quite a lot of tinkering to get it to work.

PCL is improving

Microsoft is working hard on bringing as many libraries to PCL as they possibly can. In part 2 of the series I already mentioned the portable HttpClient, that library finally gave us a uniform way of doing HTTP requests on multiple platforms. Between part 2 and this part Microsoft has released the PCL version of their Azure Mobile Services SDK (beware! this one has breaking changes if you’re coming over from the platform specific SDK).

Changes in my project

I decided not to use the PCL version of WAMS yet because it has breaking changes and it doesn’t help me get rid of some platform specific projects, so no real use there yet.

What I wanted to achieve for demoing purpose was to get the search functionality working on the phone. The search function on the Windows Store app uses a BlockingCollection (MSDN link) This is a thread safe collection, meaning I can safely prefetch data from one thread while loading data on the other thread. My entire search service is relying on this class (it’s an implementation of the consumer/producer pattern by the way), only problem: Windows Phone doesn’t have the BlockingCollection class. So I could either abstract the search service, change it entirely or implement my own version of the BlockingCollection. The last option seemed like the hardest one to do so I went for it. I’m not entirely sure if I got the exact same functionality of the real BlockingCollection (it does lack some methods and properties, I only implemented what I needed for my app) but here it is

Code Snippet
  1. public class BlockingCollection<T> : Queue<T>
  2. {
  3.     private readonly object _locker = new object();
  4.     private readonly Queue<T> _itemQ;
  5.     private bool _canAddItems;
  6.  
  7.     public BlockingCollection()
  8.     {
  9.         _itemQ = new Queue<T>();
  10.         _canAddItems = true;
  11.     }
  12.  
  13.     public void EnqueueItem(T item)
  14.     {
  15.         lock (_locker)
  16.         {
  17.             _itemQ.Enqueue(item); // We must pulse because we're
  18.             Monitor.Pulse(_locker); // changing a blocking condition.
  19.         }
  20.     }
  21.  
  22.     public bool TryTake(out T item, int millisecondsTimeout, CancellationToken cancellationToken)
  23.     {
  24.         cancellationToken.ThrowIfCancellationRequested();
  25.  
  26.         if (_canAddItems)
  27.         {
  28.             lock (this)
  29.             {
  30.                 try
  31.                 {
  32.                     item = Dequeue();
  33.                     return true;
  34.                 }
  35.                 catch (Exception)
  36.                 {
  37.                     item = default(T);
  38.                     return false;
  39.                 }
  40.             }
  41.         }
  42.  
  43.         item = default(T);
  44.         return false;
  45.     }
  46.  
  47.     public bool TryAdd(T item, int millisecondsTimeout, CancellationToken cancellationToken)
  48.     {
  49.         cancellationToken.ThrowIfCancellationRequested();
  50.  
  51.         if (_canAddItems)
  52.         {
  53.             lock (this)
  54.             {
  55.                 try
  56.                 {
  57.                     Enqueue(item);
  58.                     return true;
  59.                 }
  60.                 catch (Exception)
  61.                 {
  62.                     return false;
  63.                 }
  64.             }
  65.         }
  66.  
  67.         return false;
  68.     }
  69.  
  70.     public void CompleteAdding()
  71.     {
  72.         _canAddItems = false;
  73.     }
  74. }

It’s basically a Queue with some lock statements, it does work for me but I’m not responsible for any accidents that might occur Glimlach

Sharing ViewModels

All my viewmodels are in a PCL library, managed to get that to work in part 1. The ViewModelLocator can’t be made portable since some using statements are different and the WP8 version might need some other classes then the win8 version. I decided to add the Windows Store ViewModelLocator as a link into the Windows Phone 8 project, adding in some pre-processor directives made it work like a charm (I make this sound easy but it did take some time to get it just right).

Code Snippet
  1. using ComicDB.Framework;
  2. using ComicDB.SDKBroker;
  3. using ComicDB.View;
  4. using GalaSoft.MvvmLight;
  5. using GalaSoft.MvvmLight.Ioc;
  6. using Microsoft.Practices.ServiceLocation;
  7.  
  8. #if !WINDOWS_PHONE
  9. using ComicDB.Framework.WinRT;
  10. using ComicDB.SDKBroker.WinRT;
  11. #else
  12. using ComicDB.Framework.WP8;
  13. using ComicDB.SDKBroker.WP8;
  14. #endif
  15.  
  16. namespace ComicDB.ViewModel
  17. {
  18.     public class ViewModelLocator
  19.     {
  20.         public ViewModelLocator()
  21.         {
  22.             ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  23.  
  24.             if (ViewModelBase.IsInDesignModeStatic)
  25.             {
  26.                 // Create design time view services and models
  27.                 //SimpleIoc.Default.Register<IDataService, DesignDataService>();
  28.             }
  29.             else
  30.             {
  31.                 // Create run time view services and models
  32. #if !WINDOWS_PHONE
  33.                 SimpleIoc.Default.Register<ComicDB.Framework.Interface.INavigationService, ComicDB.Framework.WinRT.NavigationService>();
  34. #else
  35.                 SimpleIoc.Default.Register<ComicDB.Framework.Interface.INavigationService, ComicDB.Framework.WP8.NavigationService>();
  36. #endif
  37.                 SimpleIoc.Default.Register<IService, Service>();
  38.                 SimpleIoc.Default.Register<IMessageApi, MessageApi>();
  39.                 SimpleIoc.Default.Register<IFrameworkApi, FrameworkApi>();
  40.                 SimpleIoc.Default.Register<IDispatcher, Dispatcher>();
  41.                 SimpleIoc.Default.Register<INetworkApi, NetworkApi>();
  42.             }
  43.  
  44.             //register views
  45. #if !WINDOWS_PHONE
  46.             SimpleIoc.Default.Register<IMainPage, MainPage>();
  47.             SimpleIoc.Default.Register<IVolumeDetailPage, VolumeDetailPage>();
  48.             SimpleIoc.Default.Register<ICharacterDetailPage, CharacterDetailPage>();
  49.             SimpleIoc.Default.Register<ICollectionPage, CollectionPage>();
  50.             SimpleIoc.Default.Register<IDetailPage, DetailPage>();
  51.             SimpleIoc.Default.Register<IIssueDetailPage, IssueDetailPage>();
  52.             SimpleIoc.Default.Register<ILocationDetailPage, LocationDetailPage>();
  53.             SimpleIoc.Default.Register<INewsFeedPage, NewsFeedPage>();
  54.             SimpleIoc.Default.Register<IPersonDetailPage, PersonDetailPage>();
  55.             SimpleIoc.Default.Register<IStoryArcDetailPage, StoryArcDetailPage>();
  56.             SimpleIoc.Default.Register<ITeamDetailPage, TeamDetailPage>();
  57. #endif
  58.             //register viewmodels
  59.             SimpleIoc.Default.Register<MainViewModel>();
  60.             SimpleIoc.Default.Register<VolumeDetailViewModel>(true);
  61.             SimpleIoc.Default.Register<CharacterDetailViewModel>(true);
  62.             SimpleIoc.Default.Register<TeamDetailViewModel>(true);
  63.             SimpleIoc.Default.Register<IssueDetailViewModel>(true);
  64.             SimpleIoc.Default.Register<SearchViewModel>();
  65.             SimpleIoc.Default.Register<DetailViewModel>(true);
  66.             SimpleIoc.Default.Register<StoryArcDetailViewModel>(true);
  67.             SimpleIoc.Default.Register<LocationDetailViewModel>(true);
  68.             SimpleIoc.Default.Register<PersonDetailViewModel>(true);
  69.             SimpleIoc.Default.Register<CollectionViewModel>();
  70.             SimpleIoc.Default.Register<NewsFeedViewModel>(true);
  71.         }
  72.  
  73.         public MainViewModel Main
  74.         {
  75.             get
  76.             {
  77.                 return ServiceLocator.Current.GetInstance<MainViewModel>();
  78.             }
  79.         }
  80.         //... all other VM properties follow here, left out for demo purpose

The pre-processor directives make the class look a bit dirty but it does get the job done.

At this point the WP8 app started and showed me the mainpage, with the mainviewmodel being its datacontext. Now I wanted to add an appbar with a searchbutton, a few problems there:

  • the default appbar is not bindable (solved with Cimbalino)
  • the mainviewmodel doesn’t have a command to navigate to the searchpage since Windows Store uses the Search charm

I decided to take the quick and dirty solution here so I added a normal appbar with a button and a navigation statement in code behind. The SearchPage has SearchViewModel as datacontext. In Windows Store it was normal for the SearchText property to be immediately holding a value since it came from the Search charm, not the case in WP8. Small change to the viewmodel so that it doesn’t fire its Search function when SearchText is empty or null. This was the result after all my hard work

 

Mission accomplished!

Conclusion

PCL still has a long way to go but it is improving, and for some cases it can actually already be very useful (for example to share model classes over different platforms).

I would however advice against going for maximum code reuse, it all sounds great but the reality is very different. I had to make a lot of decisions, change quite a lot of architecture and even add missing classes (like the BlockingCollection).

My advice if you want to build a multiplatform app: use PCL to share your model, maybe even some small framework with helper classes, but build a custom implementation of service layers and viewmodels for each platform, it will save you a lot of hassle and probably even time. If you do decide to go for maximum code reuse, make sure that you really really think about it when you design your architecture, make sure that every little thing has an abstraction better one interface too many than having to rewrite a class.

Here’s a comparing screenshot between the solution before and after adding the WP8 project and refactoring everything.


Tags:

.Net | Devices | Metro | PCL | Patterns | WP8 | WinRT | Windows 8 | XAML

10 things you might have missed about MVVM Light

by Nico

Ever since I started playing with XAML based technologies (which actually isn’t that long ago) I’ve been looking into the MVVM (Model – View – ViewModel) pattern. I stumbled across MVVM Light pretty soon and liked the way it worked. Turns out I’m not the only one that likes it, there’s a whole set of developers, both hobby and professional, that really love this set of libraries. MVVM Light is, according to the author, not a framework but a set of libraries that take care of the plumbing to set up an MVVM structure and provide some extra helper classes to make life easier.

MVVM Light has changed a lot in its history, some elements were dragged out, others dragged in. Fact remains that it’s a fast, easy to use and lightweight framework. The author, Laurent Bugnion, does a great job of listening to the people that use MVVM Light, incorporating requested features and helping developers out. While talking to some of my fellow developers I’ve noticed a few times that there are certain elements of MVVM Light that others hadn’t heard of, and the same goes in the other direction. I’ve learned a lot of new things about MVVM Light just from talking with other users. Thinking about that gave me the idea of this blogpost and since those “10 things about…” posts seem to be popular, this was my chance. So here are my top 10 hidden gems of MVVM Light that you might have missed.

1. The MVVM Light installer

This one might seem a bit obvious, but in this NuGet driven world we would forget the added benefit of an installer. MVVM Light has an MSI installer that not only installs the binaries on your drive but it also provides project and itemtemplates in Visual Studio, along with a list of snippets. In case the Visual Studio 2012 update 2 removed your templates, reinstall the VSIX from C:\Program Files (x86)\Laurent Bugnion (GalaSoft)\Mvvm Light Toolkit\Vsix that should put the project templates back in place.

2. Constructor injection

This one is just awesome, and is actually a feature that can be found in most DI frameworks. MVVM Light uses SimpleIoc to register viewmodels and service classes at application launch (or during the app lifetime). Constructor injection means that you can specify a parameter in a class his constructor. When that class gets instantiated SimpleIoc will try to find a registered class of the same type as the parameter, when it finds one, that instance will get injected as the parameter of the constructor. Here’s an example, let’s say that in the ViewModelLocator, we register a navigation service.

Code Snippet
  1. SimpleIoc.Default.Register<INavigationService, NavigationService>();

We state here that we want to register an INavigationService in the IOC container, when it creates the instance we want it to be of type NavigationService. This “record” in the IOC container doesn’t have an instance yet, it gets instantiated when we fetch it from the container the first time. There are some occasions where you would want to create an instance of a class immediately when it gets registered. the Register<T> function of SimpleIoc has an overload to do just that.

Code Snippet
  1. SimpleIoc.Default.Register<INavigationService, NavigationService>(true);

Just pass in true as a parameter and it will create an instance right there and then.

Now we want to use the NavigationService in the MainViewModel.

Code Snippet
  1. ///<summary>
  2. /// Initializes a new instance of the MainViewModel class.
  3. ///</summary>
  4. public MainViewModel(INavigationService navigationService)
  5. {
  6.     
  7. }

SimpleIoc will search for a registered class of type INavigationService and will inject it in this constructor. This saves us the hassle of manually contacting the IOC container and requesting the correct instance.

WARNING: do be careful with this, the order in which you register your classes with the IOC container can be important, especially when using the overload to create instances. If I would create the MainViewModel before the NavigationService is registered I would get a nullreference exception. So be aware of that.

3. SimpleIoc to simple? replace it!

The SimpleIoc library works great and is a cool, lightweight addition to MVVM Light, but it is actually really lightweight. It is a very realistic scenario that for larger apps the SimpleIoc just won’t do (or you’re like me and want to try out how hard it is to replace it with another one). In this example I’m going to replace SimpleIoc with AutoFac, another well known and very powerful IOC service.

First of all, we’re going to need the AutoFac libraries and the extra library that allows us to use the ServiceLocator, just like SimpleIoc does. So either from the package manager console or from the UI, add the CommonServiceLocator extra for AutoFac, the AutoFac libraries are a dependency so they’ll get installed as well. I’m using a brand new Windows Phone 8 project for this, started from the MVVM Light project template.

Code Snippet
  1. Install-Package Autofac.Extras.CommonServiceLocator

The only place we’ll need to change some code is in the ViewModelLocator.

This is the new ViewModelLocator constructor, I’ve put the old SimpleIoc code in comments so it’s easy to compare

Code Snippet
  1. static ViewModelLocator()
  2. {
  3.     var container = newContainerBuilder();
  4.  
  5.     //ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  6.     ServiceLocator.SetLocatorProvider(() => newAutofacServiceLocator(container.Build()));
  7.  
  8.     if (ViewModelBase.IsInDesignModeStatic)
  9.     {
  10.         //SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
  11.         container.RegisterType<Design.DesignDataService>().As<IDataService>();
  12.     }
  13.     else
  14.     {
  15.         //SimpleIoc.Default.Register<IDataService, DataService>();
  16.         container.RegisterType<DataService>().As<IDataService>();
  17.     }
  18.  
  19.     //SimpleIoc.Default.Register<MainViewModel>();
  20.     container.RegisterType<MainViewModel>();
  21. }

And that’s it, we declare a ContainerBuilder, set it as the LocatorProvider. The container is then used to register everything we need. The SimpleIoc overload that creates an instance upon registering would look something like this in AutoFac.

Code Snippet
  1. container.RegisterInstance(newDataService()).As<IDataService>();

That’s it, constructor injection should still work exactly like before with SimpleIoc.

4. Built-in messages

MVVM Light has something called the messenger, it registers classes as listeners and can send messages to them. This is commonly used to do communication between viewmodels. Generally I would create a message class for each type of message that I want to send, but MVVM Light has some build in messages that we can use.

GenericMessage<T>(T content) A message that can contain whatever of type T.

Code Snippet
  1. Messenger.Default.Send(newGenericMessage<string>("my message"));
NotificationMessage(string notification)a message that contains a notification. this might be
used to send a notification to a notification factory that will show the message in the preferred way.
Code Snippet
  1. try
  2. {
  3.     //try something
  4. }
  5. catch (Exception ex)
  6. {
  7.     Messenger.Default.Send(newNotificationMessage(ex.Message));
  8. }

There’s also a NotificationMessage<T>(T notification) should you need it.

The next one is NotificationMessageAction(string notification, Action callback) basically the same as the NotificationMessage but you can add a callback action that will fire once the message is received. This one also has the generic implementation just like NotificationMessage.

DialogMessage(string content, Action<MessageBoxResult> callback) 
This message is meant to ask the user to input something and it will return the result of that input in the
MessageBoxResult. MessageBoxResult is an enum that lives in System.Windows
Code Snippet
  1. publicenumMessageBoxResult
  2. {
  3.   None = 0,
  4.   OK = 1,
  5.   Cancel = 2,
  6.   Yes = 6,
  7.   No = 7,
  8. }

 

Code Snippet
  1. Messenger.Default.Send(newDialogMessage("Are you sure?", result =>
  2.     {
  3.         if (result == MessageBoxResult.Yes)
  4.         {
  5.             //do something
  6.         }
  7.     }));

The DialogMessage class inherits from GenericMessage<string>

PropertyChangedMessage(T oldValue, T newValue, string propertyName)
The PropertyChangedMessage is meant to use like the RaisePropertyChanged implementation. This is great when multiple 
viewmodels need to respond to a changed property.
Code Snippet
  1. publicstring WelcomeTitle
  2. {
  3.     get
  4.     {
  5.         return _welcomeTitle;
  6.     }
  7.  
  8.     set
  9.     {
  10.         if (_welcomeTitle == value)
  11.         {
  12.             return;
  13.         }
  14.  
  15.         Messenger.Default.Send(newPropertyChangedMessage<string>(_welcomeTitle, value, "WelcomeTitle"));
  16.  
  17.         _welcomeTitle = value;
  18.         RaisePropertyChanged(WelcomeTitlePropertyName);
  19.     }
  20. }

Be careful when registering listeners, try to use as many different types of messages as makes sense. You don’t want a wrong listener to receive a message because it happens to listen to the same type of message. To register a listener do this:

Code Snippet
  1. Messenger.Default.Register<PropertyChangedMessage<string>>(this, message =>
  2.     {
  3.         var a = message.NewValue;
  4.         //do something
  5.     } );

5. Portable libraries

MVVM Light is available on every XAML based platform. And it comes with a portable version now. The portable version is a separate library on NuGet.

Code Snippet
  1. Install-Package Portable.MvvmLightLibs

If you decide to use the portable version, make sure that every project in your solution that needs the MVVM Light libraries references the portable version. It does not work together with the “normal” MVVM Light libraries. When you use the PCL version, you can put your viewmodels in a separate, portable library and share them over, for example, a Windows Store and a Windows Phone app.

6. Event to Command behavior

MVVM Light has an ICommand implementation called RelayCommand that can be used to bind commands to actions. Like for example a button in XAML has a Command property that can be bound to an ICommand on its datacontext, so that when the button is clicked the ICommand will fire. Unfortunately not every XAML UI element has a bindable command property for every event that they can trigger and that’s where EventToCommand comes into play. With EventToCommand you can bind any event from a XAML UI element to an ICommand in the viewmodel.

First we’ll need two namespaces in our XAML page

Code Snippet
  1. xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
  2. xmlns:command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8"

Let’s say that we want to use the Tap event on a stackpanel.

Code Snippet
  1. <StackPanel Grid.Row="0" Orientation="Horizontal">
  2.     <i:Interaction.Triggers>
  3.         <i:EventTrigger EventName="Tap">
  4.             <command:EventToCommand Command="{Binding GoToCommand}" CommandParameter="Edit" />
  5.         </i:EventTrigger>
  6.     </i:Interaction.Triggers>

Line 3 specifies the event that we want to handle, note that this is a string so be aware of typos. Line 4 binds the actual command and can even pass a parameter to the ICommand implementation.

Code Snippet
  1. privateRelayCommand<string> _goToCommand;
  2. publicRelayCommand<string> GoToCommand
  3. {
  4.     get { return _goToCommand jQuery15206875578026641675_1366095632942 (_goToCommand = newRelayCommand<string>(NavigateAway)); }
  5. }

The NavigateAway method has this signature

Code Snippet
  1. privatevoid NavigateAway(string parameter)

The parameter will be the word “Edit” in this case as that’s what we’ve specified in the XAML. We can even pass the eventargs from the event to the Command by changing line 4 from the XAML snippet to this

Code Snippet
  1. <command:EventToCommand PassEventArgsToCommand="True" Command="{Binding GoToCommand}" />

Windows Store applications don’t have these behaviors out of the box so you won’t be able to use EventToCommand there unless you install the Win8nl toolkit from NuGet. Joost Van Schaik has build his own implementation of behaviors in WinRT and thanks to his efforts (and of some other people that have helped in the project) we can now use EventToCommand in WinRT.

7. DispatcherHelper

Since .net 4.5 we have the await/async keywords and being the good little citizens that we are we do a lot of stuff async now. That means if we want to update something that lives on the UI thread we’ll need the Dispatcher class to marshall our action to that thread. Normally we don’t have access to the Dispatcher from our viewmodel classes. MVVM Light contains a DispatcherHelper that will execute an action on the UI thread when needed.

Code Snippet
  1. DispatcherHelper.CheckBeginInvokeOnUI(() =>
  2.     {
  3.         //do something
  4.     });

The DispatcherHelper gets initialized in the App.xaml.cs in the InitializePhoneApplication method (in a WP8 project that is).

DispatcherHelper also has a RunAsync method. The difference with the CheckBeginInvokeOnUI is that the CheckBeginInvokeOnUI will first check if it’s already on the UI thread, if it is it will just execute the action, if it isn’t it will call the RunAsync method.

8. Blendable

MVVM Light has complete Blend support, meaning you can drag and drop properties from the viewmodel onto the view to generate a binding, or you can generate design time data based on the datacontext and so on. I’m really not that good in Blend so I’m not going into detail about this one, just remember that MVVM Light was build with Blend in mind.

9. Open Source

This one you probably knew but MVVM Light is completely open source. http://mvvmlight.codeplex.com/ is the place to be if you want to dive into the source code.

10. Laurent is on Twitter and he’s a nice guy Glimlach

Laurent Bugnion, the founder of MVVM Light, is on Twitter! https://twitter.com/LBugnion he’s a great guy to chat with and very eager to help out anyone who needs help.

 

Conclusion

MVVM Light is a great library with a few hidden gems. In this article I’ve discussed 8 very interesting ones that can make your life as a developer easier. I’ve included two more extra items because 10 is a prettier number than 8 Glimlach

 

 


Tags:

.Net | MVVM Light | Windows 8 | WinRT | WP7 | WP8 | XAML

Porting a real win8 app to WP8–part 2

by Nico

Porting a real win8 app to WP8 – part 1

In part one of my adventure I described the architecture of my app and how I managed to move all viewmodels into a PCL (portable class library) but I didn’t use them yet. The main consensus of part one was that I needed to do quite some refactoring and add a lot of abstractions to the project in order to move over viewmodels to PCL projects. In part 2 I’ll describe how I got the viewmodels to work and how I re-enabled page navigation in the Windows 8 version. And with a bit of luck in part 3 I’ll be talking about the Windows Phone 8 version of this app.

A small note on part 1

I wasn’t very happy with part 1 since I needed to create some extra layers and abstractions. Since then the Microsoft Techdays have come and gone and with that two very interesting sessions that made me rethink some stuff. The session were from Laurent Bugnion (his blog, his Twitter) (the creator of the awesome MVVM Light toolkit) and Gill Cleeren (his blog, his Twitter) (a Belgian Silverlight MVP, RD and Win8 enthusiast). From Laurent I learned some tips and tricks concerning the ViewModelLocator class and specifically how to correctly use it in a portable library (more on that in part 3 since I haven’t implemented it yet). Gill gave a session on advanced MVVM tactics and one sentence kept vibrating in my mind “an extra class doesn’t cost a thing” next to that his demo app was filled with layers of abstractions way beyond the extra layers I needed to add to get the project to build again. After that session I felt reassured that I was going down a pretty good path with the revised architecture I had build in part 1. If you want to take a look at that session yourself, the recording of the SilverlightShow version is available here.

About part 2

The last couple of days I found some spare time to mess around with the project again. I’m now at the stage where the Windows Store app is using the portable ViewModels and the navigation is working properly. Those parts are what I’ll discuss here.

Using the ViewModels

Having the portable ViewModels ready it was time to switch to them. I deleted every viewmodel that was still in my client project, except for the ViewModelLocator, that one will be moved later. I registered the new abstraction layers in the ViewModelLocator, making sure that this only happened at runtime, not at designtime and tried to build the app. I couldn’t believe my eyes when I saw the message “Build succeeded”. I replaced the viewmodels in my client project with the ones in the portable library and it still builds! In case you’re interested, this is what’s getting registered in my ViewModelLocator at this time.

Code Snippet
  1. public ViewModelLocator()
  2. {
  3.     ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  4.  
  5.     if (ViewModelBase.IsInDesignModeStatic)
  6.     {
  7.         // Create design time view services and models
  8.         //SimpleIoc.Default.Register<IDataService, DesignDataService>();
  9.     }
  10.     else
  11.     {
  12.         // Create run time view services and models
  13.         SimpleIoc.Default.Register<INavigationService, NavigationService>();
  14.         SimpleIoc.Default.Register<IService, SDKBroker.WinRT.Service>();
  15.         SimpleIoc.Default.Register<IMessageApi, MessageApi>();
  16.         SimpleIoc.Default.Register<IFrameworkApi, FrameworkApi>();
  17.         SimpleIoc.Default.Register<IDispatcher, Dispatcher>();
  18.         SimpleIoc.Default.Register<INetworkApi, NetworkApi>();
  19.     }
  20.  
  21.     //register viewmodels
  22.     SimpleIoc.Default.Register<MainViewModel>();
  23.     SimpleIoc.Default.Register<VolumeDetailViewModel>(true);
  24.     SimpleIoc.Default.Register<CharacterDetailViewModel>(true);
  25.     SimpleIoc.Default.Register<TeamDetailViewModel>(true);
  26.     SimpleIoc.Default.Register<IssueDetailViewModel>(true);
  27.     SimpleIoc.Default.Register<SearchViewModel>();
  28.     SimpleIoc.Default.Register<DetailViewModel>(true);
  29.     SimpleIoc.Default.Register<StoryArcDetailViewModel>(true);
  30.     SimpleIoc.Default.Register<LocationDetailViewModel>(true);
  31.     SimpleIoc.Default.Register<PersonDetailViewModel>(true);
  32.     SimpleIoc.Default.Register<CollectionViewModel>();
  33.     SimpleIoc.Default.Register<NewsFeedViewModel>(true);
  34. }

Everything in the else block gets registered only at runtime. The viewmodels themselves can get registered at designtime just in case I ever want to incorporate designtime test data (something I really should do actually). Notice that some ViewModel registrations get passed a boolean parameter? The Register method of SimpleIoc has an optional parameter stating whether or not the object should get instantiated immediately. Since some viewmodels are listening for messages from the Messenger class in MVVM Light they need their instance right of the bat so they can register as listeners.

I tried to run the app, it started and data was coming in, I could use the button to show the search charm but no navigation was working. That made sense since all navigation commands are now going to ISomePage instead of SomePage and those interfaces weren’t doing anything yet. So I had to make every page implement the correct interface and put together a way to navigate to the correct page from the interface.

Implementing the interface is easy enough (they’re all just empty interfaces). Next problem was that those interfaces are inside of a folder called View in the ViewModel PCL and they need to be known in the Framework.WinRT project (that’s where the NavigationService lives). So I’ve added another PCL called it ComicDB.View and moved all interfaces there. (I couldn’t reference the ViewModel project in the Framework project, it would create a circular dependency). After adding all references everything was building again but still no navigation. To get this to work I changed the Navigate method on the NavigationService from this

Code Snippet
  1. publicvirtualbool Navigate(Type destination, object parameter = null)
  2. {
  3.     try
  4.     {
  5.         _rootFrame.Navigate(destination, parameter);
  6.  
  7.         returntrue;
  8.     }
  9.     catch (Exception e)
  10.     {
  11.         returnfalse;
  12.     }
  13. }

to this

Code Snippet
  1. publicvirtualbool Navigate(Type destination, object parameter = null)
  2. {
  3.     try
  4.     {
  5.         NavigateToPage(destination, parameter);
  6.  
  7.         returntrue;
  8.     }
  9.     catch (Exception e)
  10.     {
  11.         returnfalse;
  12.     }
  13. }
  14.  
  15. privatevoid NavigateToPage(Type destination, object parameter)
  16. {
  17.     try
  18.     {
  19.         //get the implementation for the view
  20.         var instance = SimpleIoc.Default.GetInstance(destination);
  21.         var type = instance.GetType();
  22.  
  23.         _rootFrame.Navigate(type, parameter);
  24.     }
  25.     catch (ActivationException)
  26.     {
  27.         //no registered type found, just navigate to the destination, maybe it's not an interface
  28.         _rootFrame.Navigate(destination, parameter);                                
  29.     }
  30. }

The Navigate method passes everything to the NavigateToPage method that tries to resolve a registered instance of the passed in type, should this fail it throws an ActivationException, in that case just try to navigate. This allows us to navigate to pages that don’t use any interface. Once we get the instance out of the IOC we get its type and pass that into the navigate command of the frame. Obviously, before this starts working we need to register the pages in the IOC and that happens in the ViewModelLocator.

So to finish this part 2 of, here’s the complete constructor of my ViewModelLocator

Code Snippet
  1. public ViewModelLocator()
  2. {
  3.     ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  4.  
  5.     if (ViewModelBase.IsInDesignModeStatic)
  6.     {
  7.         // Create design time view services and models
  8.         //SimpleIoc.Default.Register<IDataService, DesignDataService>();
  9.     }
  10.     else
  11.     {
  12.         // Create run time view services and models
  13.         SimpleIoc.Default.Register<INavigationService, NavigationService>();
  14.         SimpleIoc.Default.Register<IService, SDKBroker.WinRT.Service>();
  15.         SimpleIoc.Default.Register<IMessageApi, MessageApi>();
  16.         SimpleIoc.Default.Register<IFrameworkApi, FrameworkApi>();
  17.         SimpleIoc.Default.Register<IDispatcher, Dispatcher>();
  18.         SimpleIoc.Default.Register<INetworkApi, NetworkApi>();
  19.     }
  20.  
  21.     //register views
  22.     SimpleIoc.Default.Register<IMainPage, MainPage>();
  23.     SimpleIoc.Default.Register<IVolumeDetailPage, VolumeDetailPage>();
  24.     SimpleIoc.Default.Register<ICharacterDetailPage, CharacterDetailPage>();
  25.     SimpleIoc.Default.Register<ICollectionPage, CollectionPage>();
  26.     SimpleIoc.Default.Register<IDetailPage, DetailPage>();
  27.     SimpleIoc.Default.Register<IIssueDetailPage, IssueDetailPage>();
  28.     SimpleIoc.Default.Register<ILocationDetailPage, LocationDetailPage>();
  29.     SimpleIoc.Default.Register<INewsFeedPage, NewsFeedPage>();
  30.     SimpleIoc.Default.Register<IPersonDetailPage, PersonDetailPage>();
  31.     SimpleIoc.Default.Register<IStoryArcDetailPage, StoryArcDetailPage>();
  32.     SimpleIoc.Default.Register<ITeamDetailPage, TeamDetailPage>();
  33.  
  34.     //register viewmodels
  35.     SimpleIoc.Default.Register<MainViewModel>();
  36.     SimpleIoc.Default.Register<VolumeDetailViewModel>(true);
  37.     SimpleIoc.Default.Register<CharacterDetailViewModel>(true);
  38.     SimpleIoc.Default.Register<TeamDetailViewModel>(true);
  39.     SimpleIoc.Default.Register<IssueDetailViewModel>(true);
  40.     SimpleIoc.Default.Register<SearchViewModel>();
  41.     SimpleIoc.Default.Register<DetailViewModel>(true);
  42.     SimpleIoc.Default.Register<StoryArcDetailViewModel>(true);
  43.     SimpleIoc.Default.Register<LocationDetailViewModel>(true);
  44.     SimpleIoc.Default.Register<PersonDetailViewModel>(true);
  45.     SimpleIoc.Default.Register<CollectionViewModel>();
  46.     SimpleIoc.Default.Register<NewsFeedViewModel>(true);
  47. }

It registers all my api and service layers, all my views that have an interface and all viewmodels.

Part 2 conclusion

After a rough start in Part 1 it seems that this experiment has forced me to improve my code by making me add some abstractions. This makes for easier reusable code, both on the same platform as on other platforms. The DEV branch of my app project is once again a fully functional Windows Store app that reacts and behaves exactly as the one that’s in the store right now. The next step is to refactor out the ViewModelLocator and then it should be about time to start work on the Windows Phone version. See you in part 3!


Tags:

.Net | Devices | Metro | MVVM Light | PCL | Windows 8 | WinRT | WP8

  Log in

About the author

Hi,

My name is Nico, I’m an MVP Windows Platform Development living in Belgium.
I’m currently employed as a .NET consultant at RealDolmen, one of Belgium’s leading IT single source providers.

I'm also founding member and board member of the Belgian Metro App Developer Network, a user group focussed on Windows 8 and Windows Phone development. If you're in Belgium feel free to drop by if we're doing an event. http://www.madn.be

Since June 2012 I'm a proud member of Microsoft's Extended Experts Team Belgium. And in February 2013 I became a member of DZone's Most Valuable Bloggers family.

In 2013 I became a book author and wrote "Windows 8 app projects, XAML & C# edition".

In 2014 I received the MVP award for the very first time.

I hope to get feedback from my readers either through comments, mail (nico_vermeir@hotmail.com), twitter, facebook, …

 

mvp

 

mvp

 

 

MeetLogo

 

MVBLogo

mybook

 

Month List