Part 1: Creating the Portable Library (this post)
Part 2: Portability in Silverlight and WPF: a Tale of Type Forwarders
Part 3: Portability in Metro: A CLR and WinRT Love Affair
The portable library tools have been available for several months now. The goal for this add-in to Visual Studio 2010 was to enable you to create special portable assemblies that can run on various platforms, ranging from XBox and Windows Phone 7 to various versions of the .NET Framework and Windows 8, without having to recompile them. That’s a pretty amazing feat and allows developers to avoid some crazy practices like linking source code.
With Visual Studio 11, the tools are no longer an add-in but are a built-in part of the product. You can directly create portable class libraries and build these magic assemblies that can be reused without recompiling. For many users, this is incredibly important because it means they can not only reuse their libraries between platforms like the phone and the desktop, but also can build insurance for the future. Think about it: you can build a Silverlight application today, share your libraries with a Metro application you are developing for tomorrow, and only have to branch the parts of the code that are necessary.
You may be surprised to learn just how much functionality can be shared. Property change notification, commands, even the network stacks can be shared across targets. The purpose of this post is to summarize some of the capabilities, show you how to build a project that shares portable libraries, and then get into the dirty details of how the magic really works. How can we possibly have an assembly that Silverlight recognizes today work without modification or recompilation in our Windows 8 Metro application of the future? Keep on reading if you want to uncover the answer.
For this example I’ll walk you through creating a view model that executes a command and changes some text. The view model will be reused without modification in a Silverlight, WPF, and Windows 8 Metro project, along with property change notification and the implementation of ICommand. What makes this interesting is the fact that ICommand lives in very different places on these platforms.
In Silverlight and WPF, ICommand lives in the System.Windows.Input namespace. While the namespace is the same, the assemblies are not. The definition exists in System.Windows.dll for Silverlight but in WPF and the .NET Framework 4.5 it is defined in System.dll. On Windows 8 Metro, the namespace for ICommand is Windows.Xaml.UI.Input. There, it doesn’t even live in an assembly but is defined through metadata and projected by the underlying OS. How does the portable library reconcile these differences?
If you want to follow along and have Visual Studio 11 Beta Ultimate (this won’t work with Express) simply create a new solution called PortableCommandLibrary and with a project of type Visual C# –> Windows –> Portable Class Library.
Now you can modify the target frameworks. As you may imagine, the platforms you wish to target will limit your options. For example, if you want to target the phone, you won’t be able to use the Managed Extensibility Framework (MEF). If you want to target the XBox, you won’t have the networking stack available. The combination of targets will limit the portable APIs available for you to use in your portable library. The beauty is that you don’t have to figure out what’s compatible as the team has figured this out for you and will automatically restrict your options based on what you select.
Right-click the project node and go into Properties (ALT+ENTER). Click on the Change button.
This will give you the option to select the profile you wish to use. For this example, we’ll build a library that targets .NET Framework 4.5 for WPF, Silverlight 4.0 and higher, and Metro.
Great! Now take a look at the Solution Explorer under References. What is that? “Portable Subset”?
Look at the properties for the reference and you’ll see a path. Navigate to the path. Wow, now this is interesting! There are the DLLs you can safely use between the targets. You can see a redistribution list and a set of supported frameworks as well.
The magic here is worked by a new Visual Studio 11 feature called Extension SDKs. This feature allows you to use a “reference” that is actually a package of files. It solves the problem of deploying custom controls with assets and also helps us write portable code. The portable team was kind enough to figure out all of the available permutations of framework combinations and package them as specific extensions to make a seamless reference experience in Visual Studio 11. You can read Microsoft’s documentation on how to create your own SDKs here.
OK so now we’ve learned a little bit about the magic that makes this work. The SDK reference constrains what we can do to code that is portable between the target runtimes. So what next? How about create a command that can perform a single action and then disables itself? You’ll need to add a using statement for System.Windows.Input:
public class ClickOnceCommand : ICommand { public ClickOnceCommand(Action action) { _action = action; } private Action _action; private bool _canClick = true; public bool CanExecute(object parameter) { return _canClick; } public event EventHandler CanExecuteChanged; public void Execute(object parameter) { _canClick = false; _action(); var handler = CanExecuteChanged; if (handler != null) { handler(this, EventArgs.Empty); } } }
Great! Next, let’s create a view model that exposes a text property. The property invites the user to click. The view model will expose a command and feed it the action to change the text (to admonish the user not to click). The view model looks like this:
public class ViewModel : INotifyPropertyChanged { public ViewModel() { ClickCommand = new ClickOnceCommand(() => Text = "Don't Click Me"); _text = "Click Me"; } private string _text; public string Text { get { return _text; } set { _text = value; RaisePropertyChanged("Text"); } } public ICommand ClickCommand { get; private set; } protected void RaisePropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; }
Here’s the interesting part: we’ve now created a functional view model and command that will work on multiple platforms from a single assembly without recompilation. If you’re concerned about your path from now to Windows 8, consider Silverlight 5 or WPF as an interim because the following XAML will work without a single modification across all of these targets (Silverlight, WPF, and Windows 8 Metro):
<Grid> <Grid.DataContext> <portable:ViewModel/> </Grid.DataContext> <Button Content="{Binding Text}" Command="{Binding ClickCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10"/> </Grid>
Obviously it won’t always be that simple but there is a lot of opportunity for sharing code here. Don’t worry about using the XAML just yet – I’ll walk through that in the next post. You don’t have to be an expert to figure out what the goal is: we want to show a button that invites the user to click. When clicked, it will disable itself and tell the user not to click it. Simple, no?
You can build the portable library and inspect it with ildasm.exe. What I want you to notice is that the ICommand reference points to the System.Windows.dll assembly:
For Silverlight, this is fine … that’s exactly where it lives. In the .NET Framework 4.5, however, it lives in System.dll. Windows 8 Metro defines it in a different namespace: Windows.UI.Xaml.Input. So how can this single assembly work in those environments without being rebuilt?
I’ll explore the answer for WPF and the .NET Framework 4.5 in the next post. For now, take a look at the manifest that was generated for our portable assembly. Note the special tag on the external references.
More to come!