Windows/Phone 8.1 – Building for Both, Part 3

Note: the official view of //Build comes, of course, from the keynote session at //Build and the individual speaker sessions so if you find that anything that I write here seems out of sync with what you see at //Build then, of course, you should apply a pinch of salt to what I’ve written – I can be wrong and it’s early days yet.

You should also check out these 2 blog posts:

Cortana (yes!) and Many, Many Other Great Features coming in Windows Phone 8.1

Extending platform commonality through universal Windows apps

This post follows up from the previous post. I’d recommend reading that post before launching into this one and all the caveats that I applied to that post also apply here.

Having written a little in that previous post about the unified platforms, I thought I’d use this post to spin up Visual Studio and look at a “universal” app.

Making a New Universal Project

Visual Studio now has support for universal projects. These are not just for .NET applications but I’m showing the .NET variant of making a new project below. You can also do this for other language projects (e.g. HTML/JS);

clip_image002

You might also spot that it’s possible to build both a universal Portable Class Library and also a universal Windows Runtime Component – I’ll come back to one of those a little later on in the post.

Project Structure

Having made a universal project, what do you get? A couple of things that are to be expected and one that’s a “little bit different”;

clip_image004

In the Solution Explorer screenshot above, I’ve got a Windows app, a Phone app and a Shared project.

The Windows/Phone apps both have things that you might expect given the previous discussion around this not being a “one app for all” type of solution. Using the Windows 8.1 app as an example below;

clip_image006

The Windows 8.1 app has;

  1. Its own MainPage.xaml file and MainPage.xaml.cs file.
  2. Its own application manifest.
  3. Its own assets for various logos and so on.
  4. A set of references;
    1. .NET for Windows Store apps
    2. Windows 8.1 (i.e. WinRT)
    3. The shared project.

The Windows Phone 8.1 app is kind of the same;

clip_image008

With the differences being;

  1. It has some different logos because the app description is different. As a Windows Phone 8.0 developer you might spot that those logos are using the naming convention that Windows 8.1 uses for dealing with bitmaps at different scale factors (sometimes referred to as Modern Resource Technology or MRT).
  2. It has a reference to “Windows Phone 8.1” (WinRT) rather than “Windows 8.1”.

What’s perhaps more interesting here is what’s missing.

What’s in the Shared Folder?

The shared folder is a little bit of magic to me which is a bit like the “linked files” approach to things in Visual Studio today with quite a bit of extra tooling support thrown added to it.

Firstly, the shared folder appears on disk in this form;

clip_image010

It’s a real folder rather than just a concept inside of Visual Studio. The way that I’m currently thinking about the shared folder is that items within that folder are essentially built twice – once in the context of the Windows 8.1 project and another time in the context of the Windows Phone 8.1 project.

That means that if you’re going to work in the shared folder you need to be “a bit clever” in that the code you’re writing there really has to work in 2 contexts.

The App Class

By default, the App class definition has been dropped into the Shared folder by Visual Studio. Taking a look at the XAML file reveals pretty much nothing;

clip_image012

although I think it’s fairly to say that this indicates that we’re using the same base class Application and the same variant of XAML for both Windows/Phone 8.1 here.

However, having a look at the code-behind file shows a little more about what’s going on here. Here’s a little snippet;

clip_image014

A Windows 8.1 developer is going to spot this as the standard “startup” bits that Visual Studio spits out for a Windows 8.1 app but there’s a little bit more in this particular file as we have conditional compilation including some elements for WINDOWS_PHONE_APP that aren’t included for Windows 8.1. Clearly, the file gets compiled twice.

Visual Studio provides a little drop-down navigation bar such that files in the shared folder can be viewed in different contexts. For example – here’s this file in the Windows 8.1 context;

clip_image016

And notice that the code within the #if isn’t included. Now, if I switch context to Windows Phone 8.1;

clip_image018

then note that the code within the #if now is included. This also works for the XAML editor as I’ll show in the following example.

IntelliSense is also filtered using this navigation bar. As an example, there’s a class on Windows Phone 8.1 called ContentDialog which isn’t part of Windows 8.1. If I make use of this class when in the Windows Phone 8.1 context then all is good although IntelliSense warns me about availability;

clip_image020

However, if I now switch the navigation bar to the Windows 8.1 context;

clip_image022

then IntelliSense gives me nothing on that class any more as it’s not usable in Windows 8.1.

A Simple Example

Let’s say that I want to build a simple example of an app with a TextBlock and a Button and have that button launch up the browser on the device.

I can start in my shared folder and drop in a bitmap for the logo and a string resource for the label;

clip_image024

And you’d notice that the resource file format I’m using here is Resources.resw which is the Windows 8.1 resource format but which works in both situations.

I might then define a little “UI” on the phone in the MainPage.xaml file. Something like;

clip_image026

It’s worth saying here that when I come to set the Source on that Image whether I use the XAML editor or the properties grid I get IntelliSense for that Assets/web.png file even though it’s actually in the Shared folder rather than the phone project. The tooling understands what’s going on here

As an aside, I’d really like values specified via x:Uid and resource lookup to show up in the XAML designers.

I could then wrap that Image in a Button and implement a click handler;

clip_image028

And write that code in the MainPage.xaml.cs file which lives in the phone project;

clip_image030

And that works just fine.

When it comes to making a “Windows 8.1 version” of this “app”, I realise pretty quickly that I might just want to use exactly the same UI so why not just copy MainPage.xaml and MainPage.xaml.cs to the Shared folder?

clip_image032

As you might expect – the compilation system doesn’t like this much. I get an error;

clip_image034

Which seems fair. To rectify this, I can simply delete the MainPage.xaml/MainPage.xaml.cs files from the Windows/Phone projects leaving the sole remaining copy in the shared folder.

That works fine – i.e. builds, runs, all fine for both Windows and Phone.

Moving to a Portable Class Library

Rather than have code in the shared folder, I can build that code into a class library. Because of the changes in the platform, that class library can contain code which makes WinRT API calls to a wide set of platform services while still being able to target both Windows/Phone 8.1.

If I add a new class library into my project;

clip_image036

Then I can go and write some class in that class library which makes the actual platform call to the Launcher class;

using System;

using System.Threading.Tasks;

using Windows.System;

namespace CrossPlatform

{

public static class Class1

{

public static async Task Launch()

{

await Launcher.LaunchUriAsync(new Uri("http://www.microsoft.com"));

} 

}

}

The “interesting” thing about using this portable class library is that I can’t add a reference to it from my shared folder which is where the calling code lives.

Instead, I add references from both the Windows/Phone projects;

clip_image038

And then I can write code within my shared folder that uses this;

clip_image040

which feels a little unusual the first time you do it but certainly works.

Having Fun with the Shared Folder

Because of the way in which the shared folder works, it opens up some “interesting” things that you can do with it. Here’s a couple of examples that occurred to me while playing with it.

Defining UI in the Shared Folder & Styling it in Project Folders

Let’s say that I’ve got a XAML (MainPage.xaml) file in the shared folder with this piece of XAML in it;

clip_image041

You can clearly see that this is a red rectangle but if I switch the navigation bar to “Windows” I get;

clip_image043

Which is clearly a smaller, orange rectangle.

Nothing magical about that – I just changed the App.xaml which is also in the shared folder such that it included;

clip_image045

And then in each of the Windows/Phone projects I have a different styles.xaml file to re-style the rectangle for each project type (setting width, height, fill properties).

What I would find really interesting with this would be if it were possible to change layout of (e.g.) grids using this technique – I think that might open up some possibilities.

Defining Partial Classes in the Shared Folder

This is a fairly obvious thing to do. If I had some kind of scenario where I wanted to have separate UI in 2 projects for my MainPage.xaml (e.g.) then I could continue that partial class in the shared folder.

That is, in the Windows Project I might have;

clip_image047

and in the code behind file I might just have;

public sealed partial class MainPage : Page

{

public MainPage()

{

this.InitializeComponent();

}

}

and I could have the exact same page and code in my Windows Phone project.

Then I can complete this class in the Shared folder. That is, I can provide the implementation of the button’s click handler (so long as it is a common implementation or one that I’m prepared to conditionally compile);

clip_image049

I could take that a step further. I could make this code call some function on some class that doesn’t exist in the shared folder but does exist in each individual project. For example;

clip_image051

As long as I provide some implementation of Foo.Bar() in each of the Windows/Phone projects in a suitable namespace, it doesn’t really matter what that implementation does – I can use this as a cheap way of having different behaviour for the Windows/Phone platforms.

I’m not sure that makes for great maintainability but it’s another little experiment with the shared folder system to try and figure it out.

Summary

Visual Studio 2013 with the updates from //Build introduces the “universal” project which is a solution containing two projects – one for each of the Windows/Phone platforms along with a shared folder which, in my terminology, gets built twice – once in the context of a Windows application and again in the context of a Windows Phone application.

The tooling also understands this idea and does work to show you the right IntelliSense and designer when you edit a shared file such that you are viewing it in the context of a particular platform.

I’m not 100% sure just yet (because it’s so new) of exactly how I’d intend to use it but my initial thoughts are around using it to share resources (images, strings, etc) that would usually sit at the top level of my app. Beyond that, I’m still pretty attracted to the idea of sharing most code via class libraries with the big difference being that I can now build a PCL which targets both Windows/Phone 8.1. with good fidelity.

I’d still more than likely code to an MVVM+Service type model for the benefits that has but whereas in the past Windows/Phone might have been viewed as two platforms from that perspective, they are now pretty much one which is a really big step forward.