Part 1: Creating the Portable Library
Part 2: Portability in Silverlight and WPF: a Tale of Type Forwarders (this post)
Part 3: Portability in Metro: A CLR and WinRT Love Affair
Portability in Silverlight and WPF: a Tale of Type Forwarders
In the last post, I walked through creating a portable assembly that will target Silverlight 4.0 and above, .NET Framework 4.5, and Windows 8 Metro. In the assembly were a few classes that handled commands and property change notification for a simple view model. In this post I’ll show you how to reference the assembly in Silverlight and WPF and explain why it works.
The first step is to create a new Silverlight 5.0 project (just using that because it’s the latest version, I know the library will technically support 4.0). Just make a simple application (no need to have a web project as well). The project will be created with the default App.xaml and MainPage.xaml. In the solution explorer, right-click on the References node and add a reference to the PortableCommandLibrary project. Now open up the XAML for the main page. At the top, add a namespace declaration for the view model:
xmlns:portable="clr-namespace:PortableCommandLibrary;assembly=PortableCommandLibrary"
Next, paste the following XAML inside the main grid called LayoutRoot (you’ll use the exact same snippet for all of the projects in this series).
<Grid.DataContext> <portable:ViewModel/> </Grid.DataContext> <Button Content="{Binding Text}" Command="{Binding ClickCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10"/>
Now compile and run the application. You should see something like this:
If you follow the instructions, you should end up with this:
I’d love to show you how this worked with the portable library, but the answer is pretty boring. As I showed you in the last post, the portable assembly points to an ICommand interface that lives in the System.Windows.Input namespace in the System.Windows.dll assembly. If you peek inside Silverlight’s assemblies and run ildasm.exe you’ll see:
The reference can be visualized like this:
Really no magic at all – Silverlight is a lowest common denominator here. So let’s try something a little more interesting. Create a new WPF project and reference the same portable library. Add the same namespace declaration to the MainWindow.xaml file and drop in the XAML inside the Grid tag. Run the application – look familiar?
Click it.
OK, so it works the same way, but we noted earlier that the ICommand interface lives someplace different. How does this work? If you recall, the reference to System.Windows.dll in the portable library was tagged as retargetable. This tells the runtime that the target may really exist somewhere else. In fact, if you look at the references available for the .NET Framework 4.5 (here’s a tip: forget that old %windir%\Microsoft.NET\Framework\ stuff … instead, try the newer %programdir%\Reference Assemblies\Microsoft\Framework\.NETFramework\ folder), you’ll find there is a System.Windows.dll file. Pop it open with ildasm.exe and you’ll see there is no implementation in the file, only metadata. Read the manifest and you’ll come across this little gem:
Ah-hah! The portable library people have been planning this for longer than most readers suspect. There’s a nice reference now that politely invites the CLR to look somewhere else for the implementation, specifically in System.dll. If you open that assembly, you’ll see the interface is indeed defined there. So, what really happened looks a little like this for the .NET Framework 4.5:
If you’re turning pale at the thought of so many hops, don’t get worried. These tables are loaded into memory and represent very miniscule lookups. The portable team assured me that any performance cost due to a little indirection is negligible.
What I love about the approach is that it uses a lot of pieces that have been already in place but in a clever way that gives us this powerful functionality of using the same assembly in Silverlight (web) or WPF (desktop). In the next post, we’ll take it even further and see how it relates to the brand new platform of the Windows Runtime (WinRT) for a Windows 8 Metro application. How on earth do we go from this to an unmanaged code base?