0 Comments

pexels-photo-64774

If you haven’t heard or dived into .Net Standard you are in for a treat. In short it provides a way to share code across platforms but in contrast to the PCL it gives you so many more platform specific features. For an in depth overview check out the official docs.

Note: If you are starting a new Project today with Visual Studio (VS) 2015.4, you will not be able to select .Net Standard by default. But the new templates for .Net Standard will be included in Visual Studio 15.5.

Creating the .Net Standard Class Library

Migrating an existing app to .Net Standard is pretty straight forward. Step one add a .Net Standard Library to replace your PCL project.

The VS Add New Project dialog, under Visual C# select Class Library (.Net Standard)

Migrating your source code

Then drag and drop all of your existing files from the PCL project to your .Net Standard library. Note that you don’t want to copy the packages.config or any of the files under properties.

CopyFiles

Now you can delete your PCL project that you have migrated. If you do so from Visual Studio note that the Project is still available in the file system. Which means you still have it if you forgot something, but also means that you will have to delete it later on if you want to remove it from the source control workspace.

Next step is to add all the NuGet packages you have used in the PCL project. If you are having trouble adding some of the packages look out for NuGet packages that are no longer needed due to .Net Standard support such as file system access. In other cases it could be because the NuGet package has not (hopefully yet) migrated to .Net Standard. In that case check out this post and don’t forget to ask the maintainers of the project when the project will be available for .Net Standard Winking smile

Hooking up the projects

You can now add the reference to the .Net Standard in your Android and iOS project. If you created a new namespace I strongly recommend you refactor them after adding them to your projects. Or else your refactoring tool of choice will only do half the magic and you will still have some work left to do.

If you are using a UWP project please read the section bellow as you will need to make some additional steps to make it work.

Fixing the csproj for Xamarin Forms

Unfortunately when moving a Xamarin Forms app over to .Net Standard you will get weird compilation errors. The cause of this is that the XAML files are referenced in the csproj file:

02_1_RemoveEmbeddedResources

Simply remove them as they are not needed and the compile errors should be history.

When using UWP

If you are using UWP as a target (I.e. using the default Project provided up to VS 2015.4). You will have to remove and add the project anew:

If you are unsure if you really have to update your UWP project. Check if you have a project.json file in your UWP project. If the answer is yes, I’m afraid you will have to follow the following steps.

  1. Remove the UWP project from the solution in Visual Studio
  2. Rename the UWP project folder in the file explorer
  3. Add a new UWP project in Visual Studio (with the same name as the one just removed)
  4. Set the minimal supported Windows 10 version to the Fall creators update

    VS Dialog Window with Target and Minimum Version set to Fall Creators Update
  5. Add any NuGet references the just removed project had (you can peek into the project.json file in the renamed location if you are unsure which packages to add)
  6. Copy and paste all your UWP files (except the project.json)
  7. Add a reference to the Standard Library project

If you know an easier way to upgrade a UWP project, please let me know in the comments bellow Smile

Conclusion

In this post we went over the steps required to migrate an existing PCL project to .Net Standard. All the steps were done with Visual Studio 15.4.

0 Comments

Overview of UWP Apps Platforms

With UWP apps it has become easier then ever to write a single app that will run natively on all Windows 10 devices be it a phone, tablet, PC, Xbox et. al. Now we don’t just want our apps to be able to run on a device we want them to shine while they are running. In this blog post we will look at the basics on how to adopt to different screen sizes within your UWP app.

 

The devices and screen sizes

UWP runs on many different platforms some might not even come with a screen by default e.g. Internet of Things (IoT) devices or others that require a unique UI such as HoloLens which should be available for a few lucky developers later this year. Now while those platforms are very interesting in certain scenarios a wide array of apps will most probably be developed for mobile devices such as phones, tablets and phablets aka BAPHs (Big a** Phones). The unique thing about the UWPs in comparison to Android and iOS apps is that you apps will not only run on mobile devices but on desktop machines, laptops and even larger screens such as the new Surface Hub.

Windows 10 Devices
Now write once run everywhere and look like crap is easy to do. But the great benefit of creating a UWP app is that you can adopt to the different screen sizes and even adopt to different user input such as touch vs mouse and keyboard. But before we dive into the details of how we can write responsive UIs with XAML lets have a look at some basic layout rules.

Devices and screen sizes

A general split up of the devices can be made as follows.

CategoryScreen sizeWidth in Effective PixelsInputs
Phone4” to 6”340+Touch & Voice
Phablet6+” to 7”720+Touch & Voice
Tablet7” to 13.3”1024+Toch, Stylus, External keyboard*, Mouse*, Voice*
PCs and Laptops13” and greater1024+Mouse, Keyboard, Touch*, Gamepads
Surface Hub Devices55” and 84”1024+Touch, Pen, Voice, Keyboard, remote Touchpad

*: occasionally

Basic layout guides

Since UWP apps are built from the ground up to run on all kinds of different devices i.e. form factors the platform comes with many helpers that make life easier to design for multiple platforms. One basic concept are effective pixels. Effective pixels differ from actual physical pixels so 24 effective pixels on a phone will scale up to a larger physical appearance on a larger screen. The scaling of effective to physical pixels is all done by the framework and does not require any special attendance by the developer i.e. designer.

Image showing the diferent scale factors accroding to the device.

Note: Often small screens do have very large Dots Per Inch (DPI), this is also handled by the platform so even if you are running on a small device with a cheap display i.e. low DPI the text will still be readable as clearly as on a higher end display with more pixels i.e. a higher DPI.

The scaling is based on multiple of fours (4), so when defining layouts make sure they are a multiple of four e.g. 16. This will ensure that the scaling will not lead to strange effects. When using icons, rather than using images try to use a font (for example the new Segoe MDL2 Assets) that provides the icon you are looking for (or close enough). Though Windows 10 does provide a mechanism that chooses between different resolutions of an image according to the screen size, a font will always scale without any further effort.

Implementing responsive layouts that adapt to the available screen space

When working with different resolutions there are multiple layout adjustments that can be performed to improve general User Experience (UX) and – Interaction. UWP offer a variety of ways to adjust the layout of an app according to the available screen space.

  1. Changing layout of elements on a page according to form factor and available screen space
  2. Reflow e.g. adding text columns when the screen size increases
  3. Reveal information/functionality depending on the device and it’s resolution
  4. Replace elements such as navigation bars with fly out menus to accommodate smaller screen estate
  5. Change screen flow e.g. of master detail sites

So lets dive into how we can change the layout of UI elements according to the screen space.

Responsive Layout

ResponsiveDesign

One new feature of UWP apps is the possibility to adapt the layout of the controls according the available screen size i.e. the effective pixels width of the app windows. This lets the UI adapt to different screen sizes e.g. phones and tablets but also lets the UI adapt to the size a Window has on a desktop.

Lets assume you have the following screen flow and layout in your app:

Shows app running with fewer than 720 effective pixels.

The basic Layout of the app looks as follows:

<RelativePanel>
    <Rectangle x:Name="Image" Width="80" Height="80" Fill="Gray" Margin="8"></Rectangle>
    <Rectangle x:Name="TextLine1" Height="16" Width="200" Fill="Gray" RelativePanel.RightOf="Image" RelativePanel.Below="" Margin="8,8,8,4"/>
    <Rectangle x:Name="TextLine2" Height="16" Width="200" Fill="Gray" RelativePanel.RightOf="Image" RelativePanel.Below="TextLine1" RelativePanel.AlignLeftWith="TextLine1" Margin="8,8,8,4"/>
    <Rectangle x:Name="TextLine3" Height="16" Width="168" Fill="Gray" RelativePanel.RightOf="Image" RelativePanel.Below="TextLine2" RelativePanel.AlignLeftWith="TextLine1" Margin="8,8,32,4"></Rectangle>
</RelativePanel>

Note: that rendering the items in a RelativePanel allows the elements within i.e. the Rectangle to align themselves relative to one another. This is a new layout feature available in Windows 10 UWP apps which previously had to be done with a Grid or StackPanel. The benefit of using relative layouts is when we focus on how we might want to realign the content for a different screen(size).

For instance when displayed on a tablet you might not just want to show a small image next to the text but go with a banner. Using a VisualStateManagerone can easily define trigger points for the minimal window Width and  if the trigger fires adopt the layout of the predefined layout:

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup>
        <VisualState x:Name="wideView">
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="720" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Target="Image.(Width)" Value="720"/>
                <Setter Target="TextLine1.(Width)" Value="720"/>
                <Setter Target="TextLine2.(Width)" Value="720"/>
                <Setter Target="TextLine3.(Width)" Value="600"/>
                <Setter Target="TextLine1.(RelativePanel.Below)" Value="Image"/>
                <Setter Target="TextLine1.(RelativePanel.AlignLeftWith)" Value="Image"/>
            </VisualState.Setters>
        </VisualState>
        <VisualState x:Name="narrowView">
            <VisualState.Setters>
                <!-- Adjust view for narrow view -->
            </VisualState.Setters>
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="0" />
            </VisualState.StateTriggers>
        </VisualState>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

The name of the Target matches the x:Name given to the controls. The page will now re-render if the app has more then 720 effective pixels:

Shows app running with more than 720 effective pixels.

The page will also adjust when resizing the window on a Windows 10 desktop machine which allows the user to have multiple applications open at once with them seamlessly adapting to new windows sizes.

Conclusion

In this post we saw that Universal Windows Platform Apps not only run on multiple devices but that the platform provides the developers and designers with the necessary tooling of creating a great User Experience no matter the screen size and resolution without having to create multiple page layouts from the ground up and having to somehow figure out the size of the screen itself.

You can find the entire project on GitHub.

0 Comments

nuget

See how you can easily create NuGet packages to publish cross platform C# libraries that allow to integrate platform specific code in your Portable Class Library (PCL) based Projects. In a former post you can read about how to create a cross platform library and see how the library has to be consumed by the e.g. app consuming the library. This post builds up on where that last post left off and shows how we can use the library providing the OS version number in a NuGet package. So the package we want to create has the following structure:

 

  • OSVersion.Core
  • OSVersion.UWP
  • OSVersion.Droid
  • OSVersion.iOS

 

Our goal is to generate a single NuGet package which can be added to any of the above named platforms.

Note: Though this post focuses on the platforms Universal Windows Platform (UWP), Android and iOS the approach can be easily extended to support additional platforms such as .Net, Silverlight et al.

Creating the package definition

First of all we will need to install the NuGet command line tool. Make sure that you add it to your PATH. After it is added to your path you can execute the NuGet commands with PowerShell. To create a NuGet package you need a nuspec file which you can generate by executing the command):

nuget spec

The location of the nuspec file does not really matter – I tend to have it in my root directory i.e. where the Solution file is. If you open the file in your lightweight editor of choice, you can edit the package specification to your gusto or for our sample somewhat like this:

<?xml version="1.0"?>
<package >
  <metadata>
    <id>OSVersion</id>
    <version>1.0.0.3</version>
    <title>OS Version</title>
    <authors>Mark Allibone</authors>
    <owners>Mark Allibone</owners>
    <!--<licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>-->
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Get the OS version for your UWP, Android or iOS app.</description>
    <releaseNotes>This is the initial release.</releaseNotes>
    <copyright>Copyright 2015</copyright>
    <tags>OSVersion</tags>
  </metadata>
  
  <files>
    <file src="OSVersionAPI\bin\Release\OsVersionAPI.Core.dll" target="lib\portable-net45+wp8+wpa81+netcore45+monoandroid1+xamarin.ios10+UAP10\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI\bin\Release\OsVersionAPI.Core.pdb" target="lib\portable-net45+wp8+wpa81+netcore45+monoandroid1+xamarin.ios10+UAP10\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI\bin\Release\OsVersionAPI.Core.xml" target="lib\portable-net45+wp8+wpa81+netcore45+monoandroid1+xamarin.ios10+UAP10\OsVersionAPI.Core.xml" />
    
    <file src="OSVersionAPI.UWP\bin\Release\OsVersionAPI.Core.dll" target="lib\UAP10\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI.UWP\bin\Release\OsVersionAPI.Core.pdb" target="lib\UAP10\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI.UWP\bin\Release\OsVersionAPI.Core.xml" target="lib\UAP10\OsVersionAPI.Core.xml" />
    
    <file src="OSVersionAPI.Droid\bin\Release\OsVersionAPI.Core.dll" target="lib\monoandroid1\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI.Droid\bin\Release\OsVersionAPI.Core.pdb" target="lib\monoandroid1\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI.Droid\bin\Release\OsVersionAPI.Core.xml" target="lib\monoandroid1\OsVersionAPI.Core.xml" />
    
    <file src="OSVersionAPI.iOS\bin\iPhone\Release\OsVersionAPI.Core.dll" target="lib\xamarin.ios10\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI.iOS\bin\iPhone\Release\OsVersionAPI.Core.pdb" target="lib\xamarin.ios10\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI.iOS\bin\iPhone\Release\OsVersionAPI.Core.xml" target="lib\xamarin.ios10\OsVersionAPI.Core.xml" />
  </files>
</package>

Beware of the target folder structure, these names may seem a bit strange (I’m looking at you Xamarin.Android…) but these actually have to align with a pattern or else you will run into problems when installing the NuGet package. You can find the target folder names on the NuGet website.

Integrating some Metadata in the NuGet package

You are not required to add the pdb (used for Debugging) or the XML file (Code Documentation for Intellisense) but it is considered best practice and makes the life of the developer using the library easier so I would suggest you follow along with this.

To enable the XML metadata file, right click on a project under Properties, Build you can set the checkmark for XML documentation file. Now you should have an XML file in your build output.

Per default the pdb file should be generated during the build, except for iOS (it’s always you iOS isn’t it…) - anyhow, right click on your project then under Properties, Build, Advanced… set Debug Info to pdb-only.

Beware that these settings are per build Configuration so make sure you set it for Release builds as you usually ship the Release build of a library.

Packing it up

Now all that is left to do is creating the package which we can do with the following command:

nuget pack

After the package is created the next thing to do is make it available for consumption. This means either pushing the package to NuGet or creating your own NuGet repository. Due to the fact, that this here is only a demo I will go with the second option.

Integrating the package in an app

Now we can simply add the OS Version library over the package manager. Notice that we get the same result as in the former blog post but this time the developer using the library will not be required to add the library multiple times to the project i.e. this potential error source no longer exists.

So when we now run the app under UWP we get the following output.

Win10VersionNumber

Note if we would only add the NuGet package to the NativePcl.Core project the output would simply show the stub implementation.

StubVersionNumber

So all the principals that were described in the last post still apply. But adding the library has been greatly simplified.

Conclusion

In this blog post you saw how a cross platform NuGet package can be created which lends itself very well to create cross platform libraries that implement native features which have to implemented differently for each targeted platform. There are many great libraries already out in the wild that use this approach e.g. MVVM Light, SQLite, PCL Storage and many many more.

You can find the sample project on GitHub.

0 Comments

See how you can offer cross platform APIs based on C# that you can consume in Universal Windows Platform Apps (UWP), Xamarin.iOS, Xamarin.Android, Xamarin.Forms, ASP.Net and even your classic .Net WPF app. In my last post I showed how one can use platform specific libraries and code in a Portable Class Library with dependency injection. This approach is great when you are developing your own app but it gets somewhat quirky, when you want to offer a library to fellow co-workers/developers, as you force them to setup your own library through dependency injection. But there is of course another way that allows you to encapsulate your implementation details neatly while still providing platform specific features to your PCL code.

The library in this blog post will provide the OS version for a UWP, Xamarin.iOS and Xamarin.Android app.

Setting up the library

The library consists of four projects:

  • OSVersion.Core
  • OSVersion.UWP
  • OSVersion.Droid
  • OSVersion.iOS

One thing which is a bit special about all the projects is that all of their Default Namespace and the Assembly name all have the same name.

NamespaceBinaryName

In each project we implement the SystemInformationHandler.cs class, on the PCL we simply implement a stub:

public class SystemInformationHandler
{
    #region Implementation of ISystemInformationHandler

    public static string OSVersion => "Gnabber";

    #endregion
}

For the other platforms such as UWP we implement the calls to the UWP specific APIs:

public class SystemInformationHandler
{
    public static string OSVersion
    {
        get { return OsVersionString(); }
    }

    private static string OsVersionString()
    {
        string sv = AnalyticsInfo.VersionInfo.DeviceFamilyVersion;
        ulong v = ulong.Parse(sv);
        ulong v1 = (v & 0xFFFF000000000000L) >> 48;
        ulong v2 = (v & 0x0000FFFF00000000L) >> 32;
        ulong v3 = (v & 0x00000000FFFF0000L) >> 16;
        ulong v4 = (v & 0x000000000000FFFFL);

        return $"Windows {v1}.{v2}.{v3}.{v4}";
    }
}

So in the end we have implemented the generic class in the PCL and specific classes for each platform we target to support. Now lets see how we can consume this library in an app.

Consuming the library

The app will exist of the usual cross platform mobile app setup which means we will have usual suspects covering Windows, Android and iOS with a Portable Class Library aka Core to share the reusable code.

NativePclProjectOverview

In the core we have our business logic code and view models (I’m a huge fan of the MVVM Light library, to find out more just view my mvvm light posts). In the NativePcl.Core project we have a service OsVersionService.cs for returning the version number:

public class OsVersionService : IOsVersionService
{
    public string GetVersion()
    {
        return SystemInformationHandler.OSVersion;
    }
}

Reference the OSVersion.Core library as binary – DO NOT reference it as project or you will be facing compile errors in one of the next steps. Don’t ask me how I know Winking smile

Because all our assemblies of the OSVersion library will be compiled to assemblies with the same name we can’t just simply reference the project file but have to add the binary i.e. the compiled version of the library. If you are looking at the sample from GitHub, make sure to compile the solution under release build as the OSVersion is referenced via binary in the release output folder of the projects.

The method invokes the OSVersion property in the OSVersion library - leaving out the specific project e.g. UWP intent fully here. On the clients for example the Android app we have a single screen showing the version number defined in the MainView.xaml:

<Page
    x:Class="NativePcl.UWP.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:NativePcl.UWP"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding OSVersion}" VerticalAlignment="Center" HorizontalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}"></TextBlock>
    </Grid>
</Page>

And the corresponding code behind or as we are using view models MainViewModel.cs:

public class MainViewModel : ViewModelBase
{
    private readonly IOsVersionService _osVersionService;

    public MainViewModel(IOsVersionService osVersionService)
    {
        if (osVersionService == null) throw new ArgumentNullException(nameof(osVersionService));
        _osVersionService = osVersionService;
    }

    public string OSVersion => _osVersionService.GetVersion();
}

If we now run the app we will get the follow output:

coreVersion

Now this is the output we defined in the OSVersion.Core, if we now reference the binary of the OSVersion.UWP in the NativePcl.UWP project things get really interesting. Instead of receiving an error because we are adding two assemblies with the same name the compiler will prefer the platform specific library over the PCL implementation. And even though we never invoke the library directly from our NativePcl.UWP app the OS version returned now is returned from the platform specific i.e. OSVersion.UWP implementation of the GetVersion() method resulting in the following output:

uwpVersion

Now while this approach allows for writing platform independent logic in the PCL and calling platform specific implementations during runtime it is somewhat tedious as it requires that the developer will reference the correct version of the library. And all of them have the same name which is just calling for some frustrated minutes to happen due to referencing the wrong version of the library. Luckily there is a technique that allows to use the approach described above without burdening the developer consuming the library of referencing the binaries correctly. By wrapping the library in a NuGet package consuming the library is as simple as adding the package to all of your projects and the NuGet package manager will just like the build engine prefer to link the platform specific binary over the PCL library to the project. So instead of having to choose which binary to add the developer can now simply add the identical NuGet package to all of the projects and it will just work.

Conclusion

In this post you saw how to create APIs that can be consumed in the PCL and still provide platform specific functionality. For all of this to work we had to set the namespace and assembly of the projects to identical names. On the consumer one can either simply add a NuGet package containing all of the implementations i.e. PCL, UWP, Android and iOS or add the binaries of the corresponding API compilation to the app implementation e.g. OSVersion.Coreto NativePcl.Core.

This approach allows you to create APIs which can be reused across multiple platforms providing the same method definitions across the platforms.

You can find the sample on GitHub. (make sure to compile it first as a release build)

2 Comments

3856456237_f05ebd2602_o

The Portable Class Library (PCL) allows developers to share C#, F# and VB code across multiple devices, platforms and runtime environments such as .Net, Xamarin or Windows Store Apps. In this previous post you can see how you can write portable business logic and integrate it with all the various platforms. But what if you actually want to use something the other way round say the GPS position, file system etc.. What then? This is exactly his post we will look at the following topics:

  • Using Interface Segregation and Dependency Inversion to our favor
    • Interface in the PCL
    • Implementation on the Platform
  • Injecting the implementation at runtime into the PCL
  • Making the resolution of dependencies a breeze with MVVM Light

So lets get to it!

Using Dependency Injection to our favor

Remember SOLID? Well it turns out the last letter stand exactly for the pattern we will be using to solve our “How will I be able to use a platform specific feature cross platform “. The PCL code is platform independent and therefore can be used across multiple platforms, so we want to put near to all of our business logic into a PCL. Further by accessing concrete class implementations via interfaces we can define an Interface in the PCL and create it’s concrete implementation in a platform specific project.

PCLDIOverview

Dependency Injection in action

For example lets say we want to display the current OS version for each platform, this is a very platform specific feature. To access such a information in the PLC we first define an Interface in the PCL that describes the contract the implementation has to implement:

public interface ISystemInformationHandler
{
    string OSVersion { get; }
}

In the concrete platforms we can then inherit the interface and implement the handler which calls the platform specific API (bellow you see the Android implementation):

internal class SystemInformationHandler:ISystemInformationHandler
{
    #region Implementation of ISystemInformationHandler

    //public string OSVersion => System.Environment.OSVersion.ToString();
    public string OSVersion => $"Android {Android.OS.Build.VERSION.SdkInt} {Android.OS.Build.VERSION.Release}";

    #endregion
}

Now in the PCL we can have a class for example a view model that requires the handler to display the information.

public class MainViewModel : ViewModelBase
{
    private readonly ISystemInformationHandler _systemInformationHandler;

    public MainViewModel(ISystemInformationHandler systemInformationHandler)
    {
        if (systemInformationHandler == null) throw new ArgumentNullException(nameof(systemInformationHandler));
        _systemInformationHandler = systemInformationHandler;
    }

    public string OSVersion => _systemInformationHandler.OSVersion;
}

The view model requires as a parameter argument an instance of the IOSVersionHandler interface. So when we create an instance of the MainViewModel in the platform project, we can simply create an instance of interface and pass it into the view model when we create it.

var mainViewModel = new MainViewModel(new SystemInformationHandler());

And receive the following output for e.g. Android:

 

Cross platform Dependency resolution with MVVM Lights

Now resolving all of these dependencies by hand can get very tedious over time. You might have noticed that I’m using MVVM Light which comes with a lightweight Dependency Injection Container called Simple IoC. Lets see how we can use this component to further streamline our cross platform development efforts.

Note:for an introduction to MVVM Light please refer to this blog post for AndroidoriOSto get you started with the basics.

In the PCL we have the ViewModelLocator.cs which defines all of the instances used, but without the platform specific resolution.

public class ViewModelLocator
{
    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic)
        {
            // Create design time view services and models
            SimpleIoc.Default.Register<ISystemInformationHandler, SystemInformationHandlerStub>();
        }

        SimpleIoc.Default.Register<MainViewModel>();
    }

    public MainViewModel Main
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainViewModel>();
        }
    }
}

On each platform we now extend the Locator and register the platform specific classes i.e. resolution for interfaces.

internal class Locator : ViewModelLocator
{
    private static readonly Lazy<Locator> _locator = new Lazy<Locator>(() => new Locator(), LazyThreadSafetyMode.PublicationOnly);
    public static Locator Instance => _locator.Value;

    private Locator()
    {
        SimpleIoc.Default.Register<ISystemInformationHandler, SystemInformationHandler>();
    }
}

Now we can simply request an instance of the view model (MVVM Light per default only creates one instance for each registered class) and use it. In Android this would look something like this in the MainActivity.cs:

[Activity(Label = "PclDISample.Droid", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
    #region UI Controls

    private TextView OSVersion => FindViewById<TextView>(Resource.Id.OSVersion);

    #endregion

    private MainViewModel VM => Locator.Instance.Main;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        // Get our button from the layout resource,
        // and attach an event to it
        OSVersion.Text = VM.OSVersion;

        var mainViewModel = new MainViewModel(new SystemInformationHandler());
    }
}

In Windows 10 we can simply set the Datacontext accordingly in XAML:

<Page
    x:Class="PclDISample.UWP.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PclDISample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding OSVersion}" VerticalAlignment="Center" HorizontalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}"></TextBlock>
    </Grid>
</Page>

As you can see once all is registered with the simple Inversion of Control Container (IoC) of MVVM Light all of the dependency resolution will be performed automatically. If a dependency is missing, an exception will be thrown at runtime (not during compilation), so make sure to test all your views, user controls et al that they load correctly.

Conclusion

In this post you saw how you can use Dependency Injection to provide platform specific features to cross platform code located in the PCL without creating any circular dependency errors. By using interfaces in the PCL and injecting the concrete implementations during runtime we can create thin wrappers that provide platform specific features through a generic defined interface. Finally we saw how we can use MVVM Light to create a more manageable and more manageable dependency resolution with the Simple IoC Locator.

You can find the complete sample on GitHub.

Big thanks to Laurent Bugnion the creator the MVVM Light.