On September 25th and November 21st I talked about MVVM as a pattern to build apps, as well as code sharing strategies for Windows and Windows Phone projects through either Portable Class Libraries or file linking. I’m sharing the sample projects I used in those talks here for reference. You can find the slides used in these talks on the MSDN The Netherlands Team Blog.
Please note I’m using an IMDb API in these sample projects, which is not meant in any way for public consumption. I’m only using it for educational purposes and it should not be used in commercial projects.
If you attended the session, you already know I explicitly used my own implementation of MVVM as opposed to using frameworks like MVVM Light Toolkit or Caliburn Micro. The basic architecture of the solution is outlined in the schematic below:
In the MVVM_Base download at the bottom of this post, you’ll find the base Windows 8.1 app that implements this architecture, complete with sample data in the new JSON format supported in Windows 8.1 apps.
Portable Class Libraries
One of the options to share your code across Windows and Windows Phone is using Portable Class Libraries. The great thing about Portable Class Libraries (PCLs) is that it provides a way around the hard coupling between the type of class library you can reference from a specific app project. Traditionally you can only reference Windows Phone class libraries from a Windows Phone app project and the same goes for Windows Store, but with PCLs, you can reference the same library from a Windows Store, Windows Phone and even .NET and Silverlight project.
The way PCLs work is that it creates a subset of APIs that are accessible across the compatible platforms you select. For instance, you want to support Windows Phone 8 and Windows 8.1 projects in your PCL and thus it creates a subset of the APIs that are available across both platforms to be used in the PCL. The good thing about this approach is that it gives you access to all the APIs that overlap between the platforms, but unfortunately it does require some additional work to get around the limitations this poses.
In the Shared_PCL download at the bottom of this post you can see a simple implementation of a DownloadClient which should give you a general idea on how to overcome the API limitations in PCLs. The architecture in that project is as follows (sharing a lot of code in the PCL, but still requiring some code in the specific app projects due to API limitations):
Please note that my implementation assumes IValueConverter isn’t available in PCL and the WebClient/HttpClient discrepancy requires the DownloadClient implementation, but both of these can be overcome (by adding a reference to PresentationFramework.dll and Portable HttpClient respectively). The reason I left these in there is to illustrate the ways to overcome such hurdles.
Another approach to share code is by linking the source files between different projects. This way you have to creat
e separate class libraries for both Windows and Windows Phone, but you have access to the full API set for either in these library projects. By using file linking, you keep a single source file for a given class and you use compiler directives to distinguish between code for either platform. For example:
var httpClient = new HttpClient();
var response = await httpClient.GetAsync("http://someurl.com");
var responseString = await response.Content.ReadAsStringAsync();
var webClient = new WebClient();
var responseString = await webClient.DownloadStringTaskAsync("http://someurl.com");
This way, the correct code gets compiled for each platform, allowing the source file to be used in both a Windows and Windows Phone project. Obviously your code will become more complex to read once you start adding more and more of these compiler directives.
In the Shared_Linked project at the bottom of this post you’ll find an example of how to share the ImdbTopViewer app between Windows and Windows Phone through file linking. More code can be shared, because we don’t have to take any API limitations into account, so the overall architecture will look like this: