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:

Leveraging C# Partial Classes and Methods in Windows Universal Apps

There’s a number of ways we could implement platform specific code in Windows Universal Apps which I’ll cover in future articles.

In this article we’ll look at an often underused feature of C#: partial classes and methods.

Quick Overview

Partial classes allow us to split the definition of a class over multiple .cs files. The files all contain the same namespace and class names, but the class name is preceded by the partial keyword modifier.

Partial methods allow a method to be defined but that doesn’t contain an implementation, the implementation can then be provided in another partial class file.

(Check out my C# Tips eBook for more info on partial types.)

Using Simple Conditional Compilation Directives

If you want to get an overview of Universal Apps, check out this previous article.

For the sake of this demo, say we have a class “Identity” that displays a message box stating whether we’re in a Windows Store or Phone app.

We could do this using conditional directives:

using System;
using System.Threading.Tasks;
using Windows.UI.Popups;

namespace UsingPartials
{
    public class Identity
    {             
        public async Task WhoAmI()
        {
            string message = CalcMessage();

#if WINDOWS_APP

            message = "I'm a Windows Store App!";

#elif WINDOWS_PHONE_APP

            message = "I'm a Windows Phone App!";            

#endif

            var dialog = new MessageDialog(message);
            await dialog.ShowAsync();
        }
        
    }
}

And from a button click event handler in both the apps:

private async void WhoAmI_Click(object sender, RoutedEventArgs e)
{
    var id = new Identity();

    await id.WhoAmI();
}

Clicking the button in the apps results in the following message boxes being displayed:

image

 

image

 

Refactoring to Partial

So this is a simple example, but if there were lots of these conditional directives, we can tidy things up a little.

The idea is that the shared class “Identity” is made partial:

public partial class Identity

This class still contains the method that’s called from each of the apps, but this time the creation of the content of the message is delegated to a method called “CalcMessage”. This method sets the private field to be used in the dialog.

In the “Identity” class, the “CalcMessage” is declared as a partial method. This means that it doesn’t contain an implementation, but the “WhoAmI” method can still call it.

The actual implementation of the code that decides on the message is unique to the two apps.

So now the “Identity” class now looks like this:

using System;
using System.Threading.Tasks;
using Windows.UI.Popups;

namespace UsingPartials
{
    public partial class Identity
    {
        string _message;

        public async Task WhoAmI()
        {
            CalcMessage();

            var dialog = new MessageDialog(_message);
            await dialog.ShowAsync();
        }

        partial void CalcMessage();    
    }
}

We now create a new class file in the Windows Store app:

namespace UsingPartials
{
    public partial class Identity
    {
        partial void CalcMessage()
        {            
            _message = "I'm a Windows Store App!";
        }
    }
}

And another one in the Phone app:

namespace UsingPartials
{
    public partial class Identity
    {
        partial void CalcMessage()
        {
            _message = "I'm a Windows Phone App!";
        }
    }
}

Now the implementation of CalcMessage can be different for both platforms, but other code can still be shared in the shared project version of Identity.cs.

We also now don’t have any conditional directives in use.

If we only have one or two of these conditional directives, then it’s probably easier to just keep them as is, but if there are lots of them and it’s making readability harder then partials may be a useful alternative.

SHARE:

Getting Started Building a Universal Windows App

Universal Windows apps promise to enable the sharing of app code between Windows 8.1 Store apps and Windows Phone 8.1 apps.

In this demo, we’ll create a simple app and see how much work we can share between the two platforms. The sample code and design is probably not how we’d choose to implement a final solution but it will suffice for demo purposes.

Getting Started

Install Visual Studio 2013 Update 2.

Create a new project, head to the Visual C#, Store Apps, Universal Apps; choose the Blank App (Universal Apps) as the following screenshot shows. Name the app “Speechless”.

Visual Studio Universal App Create New Project

Once the solution is created, there will be 3 projects, one for Windows Store, one for Windows Phone, and a third project where we can put all the code we want to share between the two apps.

Universal App Solution

Creating a Shared Class

First off let’s create a class that we can share between apps:

solution screenshot

using System.Collections.Generic;

namespace Speechless
{
    static class Messages
    {
        public static IEnumerable<string> Greetings
        {
            get
            {
                yield return "Hello";
                yield return "Yo!";
                yield return "What's up?";
                yield return "Good day sir!";
            }
        }
    }
}

This just gives a few greetings that the user can choose from. Because this class was added in the Speechless.Shared project, it can be used from both apps.

So we could just go and create some XAML in each app and use this class, but let’s see if we can actually share XAML between apps to further reduce effort.

Creating a shared User Control

In the Speechless.Shared project, add a new item of type User Control called “ChooseGreatingControl.xaml”.

Add some XAML:

<UserControl
    x:Class="Speechless.ChooseGreatingControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Speechless"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400"    
    Width="300">
    
    <Grid>
        <StackPanel>
            <ComboBox Name="GreetingChoice" ></ComboBox>
            <Button Name="SayIt" Click="SayIt_OnClick">Speak</Button>
        </StackPanel>
    </Grid>
</UserControl>

This gives the user a ComboBox to choose which greeting to speak.

In the code behind:

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Speechless
{
    public sealed partial class ChooseGreatingControl : UserControl
    {
        public ChooseGreatingControl()
        {
            this.InitializeComponent();

            GreetingChoice.ItemsSource = Messages.Greetings;

            GreetingChoice.SelectedIndex = 0;
        }

        private async void SayIt_OnClick(object sender, RoutedEventArgs e)
        {
        }
    }
}

Here we’re just wiring up the ComboBox items to those in the Messages class and setting the default selected item to the first one.

Next let’s try to add some code to do some text to speech:

private async void SayIt_OnClick(object sender, RoutedEventArgs e)
{
    var sayWhat = GreetingChoice.SelectedValue as string;

    var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();

    Windows.Media.SpeechSynthesis.SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(sayWhat);

    var mediaElement = new MediaElement();
    mediaElement.SetSource(stream, stream.ContentType);
    mediaElement.Play();
}

So now we have some UI XAML and some code, let’s see how easy it is to share this user control between the two apps.

Using the Same User Control from Both Windows Store and Windows Phone Apps

In the MainPage.xaml of the Windows Store app project, let’s add an instance of the user control:

<Page
    x:Class="Speechless.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Speechless"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <local:ChooseGreatingControl></local:ChooseGreatingControl>
    </Grid>
</Page>

Let’s go and do the same for the Windows Phone app:

<Page
    x:Class="Speechless.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Speechless"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <local:ChooseGreatingControl></local:ChooseGreatingControl>
    </Grid>
</Page>

Running the Apps

So lets try running now, first the Windows Store app (which is selected as the default start-up app), so F5…

Windows Store app screenshot

Clicking the Speak button works, and speaks outputs the selected greeting.

So let’s try the Windows Phone app, select it as the start-up app and hit F5…

System.UnauthorizedAccessException

This is because we need to add the Microphone capability to the Windows Phone app, once this is done the app runs and works as expected:

Windows Phone screenshot

Conclusions?

This is pretty cool. Having written an app in the past  that targets both Windows Store and Windows Phone this shared project makes things SO much easier – no linked file frustrations.

The next app I start writing (whether Store or Phone) I’ll use this Universal template just so if I want to port it to the other platform it will be ready to go.

It’s going to be interesting mixing this approach with Portable Class Libraries as well. Also a framework such as MVVMLight.

If there is code in the Shared project that only applies to either Store or Phone, we can use the predefined directives:

#if WINDOWS_APP
            // Store only app specific code here
#else
            // Phone only app specific code here
#endif

Whilst I don’t know what the plans are regarding Xbox One, it would be cool to have an Xbox One app store and we could just add an “Xbox One App” to our Universal Apps solution, build, and have the same app with most of the code and UI shared between Windows Store, Windows Phone, and Xbox One.

Exciting times!

SHARE:

Universal Windows App Paper Prototype

In honour of the announcement of universal Windows apps, I though I’d create a simple one page paper prototyping template to visualise what an app would look like on both a PC/tablet and a Windows Phone. This template compliments my previous Windows 8 paper prototypes.

Universal Windows Apps Paper Protoype template

SHARE:

Portable Class Library (PCL) Timer when Targeting Both Windows 8 and Windows Phone using Reactive Extensions

Currently the Timer class is not available when targeting both Windows Phone 8 and Windows 8 Store Apps.

For the app I’m building I want the MVVMLight PCL ViewModel to update a property every second – the databound View then simply updates itself.

One solution is to implement your own Task based Timer as described in this Stack Overflow article.

Another approach could be to make use of Reactive Extensions Observable.Interval method to create a sequence that updates every n-seconds.

First off add the Reactive Extensions NuGet package to your PCL project.

Next, in the ViewModel constructor (or command, etc.) create the interval stream and then tell it to execute a method every second:

var timer = Observable.Interval(TimeSpan.FromSeconds(1)).DistinctUntilChanged();

timer.ObserveOn(SynchronizationContext.Current).Subscribe(TimerTick);

 

I’m using SynchronizationContext.Current because the TimerTick method (below) updates the ViewModel property, without this there is a thread access problem.

So the TimerTick method ends up being called every second and simply updates the (MVVMLight) TotalTimeLeft property:

private void TimerTick(long l)
{
    TotalTimeLeft = DateTime.Now.Second.ToString();
}

I’m not an expert on Rx so there may be a better way of using it in this instance (or some potential hidden problems) but it’s working in the app so far (and on ARM Surface RT)…

It’s however cool to know that Rx has portable class library support.

Any Rx experts feel free to comment on a better way :)

SHARE:

50 App By Christmas: A New Challenge

So I’ve been running this series: 50 Apps by Christmas.

Currently I’ve got 29 new apps to create before Christmas 2013 (next week).

image

As I’m not going to hit this (my book has been a higher priority) I’ve decided to roll it up into a new self-challenge: 100 Apps By Christmas 2014, I’m going to call it “A Year Of Apps”.

This means I’ve effectively got to develop 71 new apps in about 53 weeks!!

One way I’m going to do this is to (by default) dual target apps for both Windows Phone and Windows Store – I count them as separate apps. By leveraging Portable Class Libraries for view models and shared code and by creating my “starter template” in Visual Studio 2013 I hope to decrease app dev times. I also intend to do some work around automating app icon design, about pages, etc. to further reduce “boilerplate” work. Hopefully I’ll be able to evolve these and release them as open source tools :)

SHARE:

50 Apps By Christmas: 6 Apps in 3 Days

This article is part of the 50 Apps by Christmas series.

image

As part of the (Australian) Appreneur challenge, I created 6 apps – the same 3 apps, but for both the Windows Phone Store and the Windows 8.1 Store.

The 3 apps are:

  • Lorem Ipsum Pro
  • Say Stuff
  • Sleepyhead Power Nap

These are each available in the Windows Phone store and Windows Store.

Say Stuff and Sleepyhead Power Nap both use text-to-speech capabilities which I’ve already written about. Both these apps were low in complexity so a simple code-behind model was used rather than any MVVM style.

More...

SHARE:

50 Apps by Christmas: Where’s My Phone App?

This article is part of the 50 Apps by Christmas series.

image

I was listening to episode episode 135 of the Windows Developer Show and an idea was discussed to help people generate an email template to send to companies who don’t yet have Windows Phone apps. So I made Where’s My Phone App?

More...

SHARE:

50 Apps by Christmas: Start Screen Splitter

This article is part of the 50 Apps by Christmas series

progress chart

Start Screen Splitter is a simple idea to help organise the tiles on the Windows Phone Start screen. The idea is to allow the user to create and pin wide tiles to vertically group tiles into different categories.

More...

SHARE: