Implementing Platform Specific Code in Universal Windows Apps with MVVMLight and Dependency Injection

In previous articles I’ve covered using MVVMLight in Universal Windows Apps and using C# partial classes and methods to implement different code on Windows Phone and Windows Store apps.

While partial classes/methods are a quick win to alter small amounts of code for each platform, overuse might become painful as the solution gets bigger. There are also limitations of partial methods such as they can only return void, they are implicitly private, cannot be virtual, etc.

If we’re using MVVMLight (or another framework or hand-rolled viewmodels) we can use dependency injection.

The viewmodel class is still shared between the two apps and doesn’t need to have partial methods which means we have more flexibility in the code we write.

As a dependency in the constructor, the viewmodel takes an instance of a class that implements an interface.

This interface-implementing class can then be two different classes, one in the phone project and one in the store project.

architecture diagram

So for example, in the shared project the following interface can be defined:

interface IGreetingService
{
    string GenerateGreeting();
}

Again in the shared project, the viewmodel is defined:

internal class MainViewModel : ViewModelBase
{
    private readonly IGreetingService _greetingService;
    private string _greeting;

    public MainViewModel(IGreetingService greetingService)
    {
        _greetingService = greetingService;

        SayHi = new RelayCommand(() => Greeting = _greetingService.GenerateGreeting());
    }

    public RelayCommand SayHi { get; set; }

    public string Greeting
    {
        get { return _greeting; }
        set { Set(() => Greeting, ref _greeting, value); }
    }
}

The key thing here is the constructor: it takes an IGreetingService.

When the SayHi command is executed, whichever instance of an IGreetingService was passed to the viewmodel, it’s GenerateGreeting() method will be called.

So in the store project the following class can be created:

public class WindowsStoreGreeter : IGreetingService
{
    public string GenerateGreeting()
    {
        return "Hello from Windows Store app!";
    }
}

And in the phone app:

public class WindowsPhoneGreeter : IGreetingService
{
    public string GenerateGreeting()
    {
        return "Hello from Windows Phone app!";
    }
}

It is in these specific implementations of the interface that the platform specific code is written.

So in the code-behind of the main window in the store app (for demonstration simplicity we’re not using a view model locator or DI library here):

public MainPage()
{
    this.InitializeComponent();

    this.DataContext = new MainViewModel(new WindowsStoreGreeter());
}

And in the phone app:

public MainPage()
{
    this.InitializeComponent();

    this.NavigationCacheMode = NavigationCacheMode.Required;

    this.DataContext = new MainViewModel(new WindowsPhoneGreeter());
}

In these code fragments a new MainViewModel is being created and supplied with a platform-specific IGreetingService implementation.

So in this way the shared MainViewModel class can still contain the majority of the code so we only have to write it once. But we still get the ability to write platform-specific code.

SHARE:

Using MVVM Light in Universal Windows Apps

I though it would be interesting to see how easy it is to define an MVVM Light view model once and then use it in both a Universal Windows Phone and Windows Store project.

So I created a new blank universal apps project and added the “MVVM Light libraries only (PCL) NuGet” package to both the Windows 8.1 project and the Windows Phone 8.1 project.

Next create a new view model class in the shared project:

using System.Linq;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace UniMvvmLight
{
    class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            Words = "Hello";

            Reverse = new RelayCommand(() =>
                                       {
                                           Words = new string(Words.ToCharArray().Reverse().ToArray());
                                       });
        }

        private string _words;
        public RelayCommand Reverse { get; set; }

        public string Words
        {
            get
            {
                return _words;
            }
            set
            {
                Set(() => Words, ref _words, value);                
            }
        }
    }
}

I’m not going to create a view model locator etc, just simply set the datacontext in the code behind of both the phone and store MainWindow:

public MainPage()
{
    this.InitializeComponent();

    this.DataContext = new MainViewModel();
}

Next define the xaml in both the MainWindow.xaml in both phone and store projects:

<Grid>
    <StackPanel>
        <TextBox Text="{Binding Words}"></TextBox>
        <Button Command="{Binding Reverse}">Reverse</Button>
    </StackPanel>
</Grid>

Now running either the phone or store app works as expected, the view model binding works as expected and clicking the button reverses the string as expected. Whilst this is not surprising, the view model in the shared project is just like having a copy of it in both app projects, even so it’s still cool.

Windows phone simulator

If we wanted to we could then leverage C# partial classes and methods to define platform-specific viewmodel code.

SHARE:

Write Less MVVM ViewModel Boilerplate Code with T4

Although code snippets can make creating our initial viewmodels easier (properties, commands,etc.) it’s still tantamount to boilerplate code. Obviously the actions that happen when a command is executed is not boilerplate, but the actual definition is.

T4 templates are built into Visual Studio and allow us to define templates that are a mix of literal output (such as HTML tags) and C# code.

We can for example create a C# for loop around some literal output, e.g. “Hello World” to output it 10 times. For more info on T4, check out MSDN.

T4 for View Model Code Generation

Rather than hand-coding viewmodels, we can define a T4 template. In this template we are able to define the view models we want generating – included both commands and properties that we want to have on those view models.

The implementation in this article creates a new abstract base class for each view model that contains our commands and properties, in addition to a command init method to create and wire-up new MVVM Light RelayCommands along with can execute hooks.

Once T4 has generated these base class view models, we inherit from them and a constructor that calls the base class’s InitCommands method.

The sample application bind some text and a button:

before clicking button

When you click the button the bound Person in the viewmodel is updated and the command is disabled:

after clicking button

 

The actual viewmodel code looks like this:

using SampleWpfApplication.Model;

namespace SampleWpfApplication.ViewModel
{
    class MainViewModel : MainViewModelBase
    {
        public MainViewModel()
        {
            InitCommands();
        }

        protected override void ExecuteLoad()
        {
            Who = new Person {Name="Jason"};
            LoadCommand.RaiseCanExecuteChanged();
        }

        protected override bool CanExecuteLoad()
        {
            return Who == null;
        }
    }
}

Note it derives from MainViewModelBase which is the generated code.

Also note there’s no Person property (called “Who”) and no RelayCommand defined.

We’ve overridden a couple of methods from the base class to get the behaviour we want and also called InitCommands in the constructor.

The fragment of the T4 template that defines the viewmodels looks like this:

/// <summary>
/// Make changes to this class to define what view models you want generating
/// </summary>
public  static class ViewModelGeneratorSettings
{   
    // ********** Which name space the view model classes will live in
    public const string OutputNameSpace = "SampleWpfApplication.ViewModel";


    public static List<ViewModelDefinition> ViewModelDefinitions
    {
        get
        {
            return new List<ViewModelDefinition>()
                   {
                       // Define your view models here
                       new ViewModelDefinition
                       {
                           Name = "MainViewModel",
                           Properties =
                           {
                               Tuple.Create("Who", "Person"), // here Who is the name of the command prop, Person is the type
                               //Tuple.Create("NextTopic", "Topic"),
                               //Tuple.Create("CurrentTopicTimeRemaining", "TimeSpan"),
                               //Tuple.Create("TotalTimeRemaining", "TimeSpan"),
                               //Tuple.Create("IsPlaying", "bool") // here IsPlaying is the name of the command prop, bool is the type
                           },
                           Commands =
                           {
                               "Load", // Name of the commands
                               //"Pause"
                           }
                       },
                       new ViewModelDefinition
                       {
                           Name = "AnotherViewModel",
                           Properties =
                           {
                               Tuple.Create("SomeProperty", "int"),
                           },
                           Commands =
                           {
                               "A",
                               "B"
                           }
                       }, // etc.
                   };
        }
    }
}

To create new viewmodels we just add new ViewModelDefinitions and specify what properties and commands we want – currently property types are specified as strings rather than actual types.

To get started and see it in action, download the sample application from GitHub and see how it fits together. The full template is here as well.

While the examples here relate to MVVM Light, the concept could be used with other frameworks.

SHARE:

Centralising RaiseCanExecuteChanged Logic in an MVVM Light Portable View Model

When working with an MVVM Light sometime we need to “tell” the view that a command’s ability to be executed has changed.

For example, when a user clicks a Start button to start a countdown, the Start button should be disabled and the pause button should then be enabled.

If we’re binding a button to an MVVM Light RelayCommand, the button will automatically disable when then RelayCommand’s CanExecute function returns false.

For this to work, when the user clicks Start, the command will execute, but then we need to tell the Start and Pause commands to raise their CanExecuteChanged events. To do this we can call the RaiseCanExecuteChanged method on each RelayCommand that logically makes sense for our application.

One approach is to put this in each property setter, for example:

public const string IsPlayingPropertyName = "IsPlaying";
protected  bool _isplaying;

public  bool IsPlaying
{
    get
    {
        return _isplaying;
    }

    set
    {
        if (_isplaying == value)
        {
            return;
        }

        RaisePropertyChanging(IsPlayingPropertyName);
        _isplaying = value;
        RaisePropertyChanged(IsPlayingPropertyName);
              
        // RAISE CANEXECUTECHANGED HERE IN PROP SETTER
        PauseCommand.RaiseCanExecuteChanged();
        StartCommand.RaiseCanExecuteChanged();
    }
}

Now when this IsPlaying property changes, the Pause and Start buttons commands can execute will be updated.

A problem with this approach is that the logic to decide which RelayCommands CanExecuteChanged event gets raised in response to which properties are changing is distributed through all the property setters in the ViewModel. This can make it hard to reason about the changes in state of the ViewModel.

One alternative approach is to centralise this logic in a single method.

More...

SHARE:

Using XAML Behaviours to stop MVVM Light Messenger Action Executing Multiple Times

In MVVM Light, when we derive our ViewModel from ViewModelBase, we inherit a Cleanup() method.

This method can be overridden, by default it will unregister all messages for the ViewModel, so calling Cleanup() on our view model will prevent multiple subscriptions occurring if we navigate back to the ViewModel and register it again.

But where do we call Cleanup() ?

One method is to get the View to call the ViewModel’s Cleanup() method when it is unloaded.

We could write a codebehind “shim” to cast the View’s DataContext to our ViewModel type then call its Cleanup() method.

Another method is to use the Behaviours SDK (XAML).

image

Once we add this reference we can add some namespaces in our View XAML:

xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"

Now in our page, we can add the following XAML:

<interactivity:Interaction.Behaviors>
    <core:EventTriggerBehavior EventName="Unloaded">
        <core:CallMethodAction TargetObject="{Binding}" MethodName="Cleanup" />
    </core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>

Now every time the Page’s Unloaded event is raised, the Cleanup() method will be called on our ViewModel, which will unregister all messages for the bound ViewModel.

SHARE:

Telling a View to display a Message Dialog from the ViewModel With MVVMLight in Windows 8.1 Store Apps

The technique below is one technique, others exist, but the design goals of this approach are:

  1. The ViewModel cannot know or reference the View
  2. The ViewModel should should not care how the View displays or interacts with the user (it could be a dialog box, a flyout, etc.)
  3. The ViewModel must be Portable Class Library compatible and View agnostic, e.g. not need to know about dialog buttons, etc.
  4. Choices the user makes in the View dialog should result in Commands being executed on the ViewModel
  5. The ViewModel must not specify the content of the message text, button labels, etc. – the View should be responsible for the text/content of the message

One way to think about these design goals is that the ViewModel is asking for some semantic message/dialog to be displayed in the View.

Defining a Message to be used with the MVVM Light Messenger

The way the ViewModel “tells” the View to create a dialog is by sending a message using the MVVM Light Messenger.

First we define a custom message:

using System.Windows.Input;
using GalaSoft.MvvmLight.Messaging;

namespace Project.Portable.ViewModel.Messages
{
    public class ShowDialogMessage : MessageBase
    {
        public ICommand Yes { get; set; }
        public ICommand No { get; set; }
        public ICommand Cancel { get; set; }
    }
}

This message allows us to define the commands that the view will call, based on the choice that the user makes in the dialog.

More...

SHARE:

MVVM Light Telling the View to play Storyboards

Sometimes you want to tell the view to play an animation (Storyboard). One simple way to do this is to define a StartStoryboardMessage class, populate this with the name of a Storyboard to play, then send it to the Messenger.

public class StartStoryboardMessage
{
    public string StoryboardName { getset; }
    public bool LoopForever { getset; }
}

In the viewmodel when you want to tell the view to play an animation:

Messenger.Default.Send(new StartStoryboardMessage { StoryboardName = "TimerFinAnimation",LoopForever=true });

The view (i.e. in the code-behind) registers for these messages:

Messenger.Default.Register<StartStoryboardMessage>(this, x => StartStoryboard(x.StoryboardName, x.LoopForever));

...

private void StartStoryboard(string storyboardName, bool loopForever)
{
    var storyboard = FindName(storyboardName) as Storyboard;
    if (storyboard != null)
    {
        if (loopForever) 
            storyboard.RepeatBehavior = RepeatBehavior.Forever;
        else
            storyboard.RepeatBehavior = new RepeatBehavior(1);
        storyboard.Begin();
    }
}

SHARE:

MVVM Light Messenger Action Executing Multiple Times

With MVVM Light you can get into a situation where you code-behind's message handler gets called multiple times.

If the ctor for the view is registering for a message then the every time the view loads another subscription will be added; then when the message is sent the are effectively 2 'listeners' which end up executing the registered Action method multiple times.

One solution to this is to make sure you un-register when the view unloads.

The example below shows the code-behind for a simple settings page that registers for a DialogMessage in the ctor, and un-registers when the page is done with.

    public partial class Settings : PhoneApplicationPage
    {
        public Settings()
        {
            InitializeComponent();
            Messenger.Default.Register<DialogMessage>(this, DialogMessageHandler);
        }
        private void DialogMessageHandler(DialogMessage message)
        {
            var result = MessageBox.Show(message.Content, message.Caption, message.Button);
            
            message.ProcessCallback(result);
        }
        private void PhoneApplicationPage_Unloaded(object sender, RoutedEventArgs e)
        {
            Messenger.Default.Unregister(this);
        }
    }

SHARE: