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);
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”;
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;
The Windows 8.1 app has;
- Its own MainPage.xaml file and MainPage.xaml.cs file.
- Its own application manifest.
- Its own assets for various logos and so on.
- A set of references;
- .NET for Windows Store apps
- Windows 8.1 (i.e. WinRT)
- The shared project.
The Windows Phone 8.1 app is kind of the same;
With the differences being;
- 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).
- 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;
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;
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;
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;
And notice that the code within the #if isn’t included. Now, if I switch context to Windows Phone 8.1;
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;
However, if I now switch the navigation bar to the Windows 8.1 context;
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;
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;
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;
And write that code in the MainPage.xaml.cs file which lives in the phone project;
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?
As you might expect – the compilation system doesn’t like this much. I get an error;
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;
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;
And then I can write code within my shared folder that uses this;
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;
You can clearly see that this is a red rectangle but if I switch the navigation bar to “Windows” I get;
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;
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;
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);
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;
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.