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.

Pingbacks and trackbacks (2)+

Add comment

Loading