In the past I wasn’t a big fan of the Portable Class Library as I felt it imposed more restrictions than necessary and would constrain/frustrate developers more than it would actually solve a problem. However, in recent times a couple of things have happened that have made this whole experience a lot better.
Firstly, we no longer need to drag out VS2010 to do Windows Phone 7 development. The new Windows Phone 8 SDK plugs into VS2012 and allows for both WP7 and WP8 app development. This means that if you’re going to be targeting multiple versions of WP you can do so in the same solution.
Next, the release of Microsoft.Bcl.Async on nuget – ok, you’re probably thinking what’s that? Well a while ago Microsoft published the Async programming CTP. Whilst it had a go-live license and could be used in your Windows Phone 7 project it was a hassle to install in VS2010 (due to a weird set of dependencies which were broken with subsequent updates to VS) and didn’t support VS2012 at all. The Microsoft.Bcl.Async package is the replacement for the Async CTP, allowing you to do asynchronous programming in WP7 apps. Of course, both Win8 and WP8 support async programming out of the box.
Ok, on to using a Portable Class Library. The concept here is that you want to build a single, managed, library that can be referenced by applications targeting different platforms. Let’s walk through a simple example.
We’re going to start by creating three different applications within the sample solution: SimplePCLTestApp.WP7, SimplePCLTestApp.WP8 and SimplePCLTestApp.Win8. As the project names suggest the projects should be targetting WP7, WP8 and Win8 respectively. We’re then going to also create a Portable Class Library called SimplePCL. Note, when you go to create the PCL you’ll see a prompt similar to the following image. This allows you to specify which frameworks your going to be targeting. In this case we’ll take the default options as we’re not going to be building for XBox.
The next thing to do is to add the Microsoft.Bcl.Async nuget package into the WP7 and PCL projects. The following image illustrates the package that you’re after.
Unfortunately at the moment when you attempt to add this package it won’t give you the option to add it to the PCL. It appears there is some incompatibilities with the current version of the nuget package for Microsoft.Bcl.Async and the PCL. Luckily it’s relatively easy to fix manually:
> Unload the PCL project
> Right-click on the PCL project and select Edit SimplePCL.csproj
> Now, replace the following element
<ItemGroup>
<!– A reference to the entire .NET Framework is automatically included –>
</ItemGroup>
With
<ItemGroup>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..packagesMicrosoft.Bcl.Async.1.0.12-betalibsl4-windowsphone71Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..packagesMicrosoft.Bcl.Async.1.0.12-betalibsl4-windowsphone71Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Phone">
<HintPath>..packagesMicrosoft.Bcl.Async.1.0.12-betalibsl4-windowsphone71Microsoft.Threading.Tasks.Extensions.Phone.dll</HintPath>
</Reference>
<Reference Include="System.Runtime">
<HintPath>..packagesMicrosoft.Bcl.1.0.11-betalibsl4-windowsphone71System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks">
<HintPath>..packagesMicrosoft.Bcl.1.0.11-betalibsl4-windowsphone71System.Threading.Tasks.dll</HintPath>
</Reference>
</ItemGroup>
> Save, and reload the PCL project
The last preparatory step is to add a reference to the PCL project to each of our applications. This is done as per normal by right-clicking the project, selecting Add Reference, and then selecting the PCL project from the solution node.
We’re now ready to start writing some code. We’ll rename Class1 to ExampleClass and add the following code:
public class ExampleClass:INotifyPropertyChanged {
private string name;
public string Name {
get { return name; }
set {
if (Name == value) return;
name = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
private readonly ManualResetEvent sleepEvent = new ManualResetEvent(false);
public async Task UpdateName(string newName) {
await Task.Factory.StartNew(() =>
{
// This will sleep waiting for a signal that will never happen!
sleepEvent.WaitOne(1000);
});
Name = newName;
}
}
This simple class illustrates a couple of different things:
– The use of INotifyPropertyChanged – almost essential for view models, which you will probably want to share across projects if you’re using MVVM. Note the OnPropertyChanged method uses the CallerMemberName attribute, rather than the property name having to be specified when the method is called.
– The UpdateName method is an asynchronous method which launches a background task using Task.StartNew. This is to simulate some long running task (eg service call, or disk I/O). There is no support for Thread.Sleep in the PCL so we’ve used a workaround which involves waiting for a reset event that will never happen.
– The Name property is updated after the background task has completed. If this method was invoked on the UI thread then it’s safe to update the Name property, since the PropertyChanged event also needs to be invoked on the UI thread to prevent a cross threading violation.
We can then add the following code to the main page of each of our applications:
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
var example = new ExampleClass();
example.PropertyChanged+=ExamplePropertyChanged;
example.Name = "Initial Name";
Debug.WriteLine("————————-");
await example.UpdateName("Updated Name");
Debug.WriteLine("————————-");
}
private void ExamplePropertyChanged(object sender, PropertyChangedEventArgs e)
{
var ex = sender as ExampleClass;
Debug.WriteLine(ex.Name);
}
Running this, in all cases, should yield the following Debug output (you may see some additional assembly/type loading information as well):
Initial Name
————————-
Updated Name
————————-
And there you have it. An example of how you can use a Portable Class Library to abstract our your platform independent code.