With the Windows 8 preview release earlier this week, developers are now faced with a whole new and exciting Microsoft stack. The Windows 8 architecture has something of a split-personality, incorporating a completely new runtime, WinRT together with the older Win32 and .NET framework. However, these sit on different sides of a physical divide in both the architecture and the user interface. For more details of this, see my earlier article.
The new WinRT APIs support both C# and XAML, having an interface that is very similar to its .NET counterparts. However, there are a number of differences, most importantly much of the UI now resides in a new namespace. It is clear that transitioning from Silverlight, WP7 or WPF development to using WinRT will be quite easy.
I am sure there exists classes of application that sit best in the Win8 Metro UI, for which you will use WinRT for development. There will also be classes of application that sit best in the Win8 classic desktop, for which you will still be using WPF and Silverlight to develop.
However … there will certainly exist a class of application that sits well in both the Metro and Desktop environment. In the Win8 preview IE does just this.
This introduces a problem, how can we share code between our Silverlight Desktop and WinRT Metro applications?
I have previously presented talks and written articles on cross-platform application development. So I thought I would grab myself a copy of the Win8 preview release and see how easy it is to code-share between a Silverlight and WinRT Metro application.
This blog post describes a simple TwitterSearch application, the Silverlight version is shown below. Simply type in a search string to see the results retrieved from twitter:
A screenshot of the TwitterSearch application built for WinRT Metro is shown below:

When code-sharing between WPF, Silverlight and WP7 applications separation of concerns and solid design patterns are essential in order to navigate the framework differences. For that reason I use the Model-View-ViewModel pattern, this makes it easy to specialise the view for each platform, where they typically differ the most. I will use this same approach for WinRT.
The code is shared between the Silverlight and Win8 Metro application by having two separate solutions which both share files via the Visual Studio file linking feature.
The TwitterSearchViewModel which backs this application simply exposes a search string property and a list of tweets:
public partial class TwitterSearchViewModel : INotifyPropertyChanged { private TweetViewModelCollection _tweets = new TweetViewModelCollection(); private IMarshalInvoke _marshalInvoke; private string _searchText = "WinRT"; public TwitterSearchViewModel(IMarshalInvoke marshalInvoke) { _marshalInvoke = marshalInvoke; } /// <summary> /// Gets / sets the search term /// </summary> public string SearchText { get { return _searchText; } set { _searchText = value; OnPropertyChanged("SearchText"); } } /// <summary> /// Gets the search results /// </summary> public TweetViewModelCollection Tweets { get { return _tweets; } set { _tweets = value; } } /// <summary> /// Gets a command that executes the search /// </summary> public ICommand ExecuteSearchCommand { get { return new DelegateCommand(() => ExecuteSearch()); } } } |
The IMarshalInvoke interface allows the view model to perform asynchronous calls via the Dispatcher, without being dependant on this UI class, more on this later.
It is here that I hit the first problem, WinRT has ICommand, but it lives in a different namespace! Time to add a WinRT compilation symbol to my WinRT project and throw in a pre-compiler directive:
#if WINRT using Windows.UI.Xaml.Input; #else using System.Windows.Input; #endif |
Now my view model compiles just fine. However, when I hooked it up with the view, my bindings were only working in one direction. After appealing to Twitter, the MSDN forums and the WPF Disciples, Laurent Bugnion kindly informed me that WinRT has two different INotifyPropertyChanged interfaces. One within System.ComponentModel and the other in Windows.UI.Xaml.Data, if you use the one from System.ComponentModel it is ignored by the WinRT binding framework. Very confusing!
Fixing this is simply a matter of adding more platform specific namespaces:
#if WINRT // used for ICommand using Windows.UI.Xaml.Input; // used for INotifyPropertyChanged using Windows.UI.Xaml.Data; #else using System.ComponentModel; using System.Windows.Input; #endif |
My original code used WebClient, which is not present in WinRT. Fortunately HttpWebRequest is present in both, so I changed my code to use that, hence the need for the IMarshalInvoke interface to marshal execution back onto the UI thread.
As a result, much of the core logic, which makes use of Linq-to-XML, in the view model is shared between both applications:
/// <summary> /// Parses the response from our twitter request, creating a list of TweetViewModel instances /// </summary> private void ParseXMLResponse(string xml) { var doc = XDocument.Parse(xml); var items = doc.Descendants(AtomConst.Entry) .Select(entryElement => new TweetViewModel() { Title = entryElement.Descendants(AtomConst.Title).Single().Value, Id = long.Parse(entryElement.Descendants(AtomConst.ID).Single().Value.Split(':')[2]), ProfileImageUrl = entryElement.Descendants(AtomConst.Link).Skip(1).First().Attribute("href").Value, Timestamp = DateTime.Parse(entryElement.Descendants(AtomConst.Published).Single().Value), Author = entryElement.Descendants(AtomConst.Name).Single().Value }); _tweets.Clear(); foreach (var item in items) { _tweets.Add(item); } } /// <summary> /// Searches for the given term /// </summary> private void ExecuteSearch() { IsSearching = true; // perform the search string uri = _twitterUrl + SearchText; HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(uri)); request.BeginGetResponse(new AsyncCallback(ReadCallback), request); } /// <summary> /// A callback that receives the search results /// </summary> private void ReadCallback(IAsyncResult asynchronousResult) { HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState; HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult); using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream())) { string resultString = streamReader1.ReadToEnd(); // marshall onto the UI thread and parse _marshalInvoke.Invoke(() => { Tweets.Clear(); ParseXMLResponse(resultString); IsSearching = false; }); } } |
This makes me happy
On a side note, whilst WinRT does not have WebClient, it actually has something much better via classes such as SyndicationFeed which make use of the new C# async and await pattern for dealing with asynchrony. Of course, using these new APIs reduces the amount of code you share with the Silverlight .NET code.
The DelegateCommand implementation again hits the same problem of the same interface being located in a different namespace, yet despite this, most of the code is shared:
#if WINRT // used for ICommand using Windows.UI.Xaml.Input; #else using System.Windows.Input; #endif namespace SLUGUK.ViewModel { public class DelegateCommand : ICommand { private Action _action; public DelegateCommand(Action action) { _action = action; } public bool CanExecute(object parameter) { return true; } #if WINRT public event Windows.UI.Xaml.EventHandler CanExecuteChanged; #else public event EventHandler CanExecuteChanged; #endif public void Execute(object parameter) { _action(); } } } |
Despite the various XAML UI controls being in a different C# namespace, they use the same URIs for their XML namespace mappings. This makes it possible to share XAML as well as C# code between your applications.
However, in much the same way as it makes little sense to share XAML between WP7 and Silverlight due to differences in form-factor and user-experience, I don’t think it makes sense to share XAML between Silverlight and Metro WinRT. The primary focus of the Win8 Metro applications is the touch-first tablet form factor, hence you would expect it to be quite different from a desktop application.
The following is the XAML for my Metro UI application:
<UserControl x:Class="WinRTMetroTwitter.View.TwitterSearchView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="using:WinRTMetroTwitter.View" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <UserControl.Resources> <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/> <local:ImageConverter x:Key="ImageConverter"/> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="#FF0C0C0C"> <Grid Margin="50" Width="400" HorizontalAlignment="Left"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal"> <TextBox Text="{Binding Path=SearchText, Mode=TwoWay}" Width="200"/> <Button Command="{Binding Path=ExecuteSearchCommand}" Content="Go!"/> <TextBlock VerticalAlignment="Center" Visibility="{Binding Path=IsSearching, Converter={StaticResource BoolToVisibilityConverter}}" Text="Searching ..." Margin="20,0,0,0" FontSize="15"/> </StackPanel> <!-- renders the search results --> <ItemsControl x:Name="itemsControl" Grid.Row="2"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Margin="5"> <Image Source="{Binding ProfileImageUrl, Converter={StaticResource ImageConverter}}" Width="96" Height="96" Stretch="UniformToFill" Margin="2" VerticalAlignment="Top"/> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Title}" TextWrapping="Wrap" FontSize="15" Width="300" HorizontalAlignment="Left"/> <StackPanel Orientation="Horizontal"> <TextBlock FontWeight="Bold" Text="{Binding Path=Author}" FontSize="15"/> <TextBlock Margin="10,0,0,0" Text="{Binding Path=Timestamp}" FontSize="15" Foreground="#333"/> </StackPanel> </StackPanel> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> <Rectangle Fill="#FF0C0C0C" Opacity="0.5" Grid.Row="1" Visibility="{Binding Path=IsSearching, Converter={StaticResource BoolToVisibilityConverter}}"/> </Grid> </Grid> </UserControl> |
If you are a Silverlight developer you will notice that everything here is standard Silverlight, it is just wired-up to different classes via the XAML namespace mappings.
I did discover that the IValueConverter signature within WinRT is a bit different. Within this application, the value conversion logic is so simple it is hardly worth code-sharing, however, it would be a very simple exercise if you wished to do so.
namespace WinRTMetroTwitter.View { public class BoolToVisibilityConverter : IValueConverter { public object Convert(object value, string typeName, object parameter, string language) { return (bool)value ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, string typeName, object parameter, string language) { throw new NotImplementedException(); } } } |
Finally, I did hit against one further problem. With WinRT it seems that there is a currently a bug which prevents ItemsControl binding to collections via INotifyCollectionChanged from working. This has been raised in the MSDN forums and I am sure it will be fixed. As a simple workaround I added the following code-behind (gasp!):
public sealed partial class TwitterSearchView : UserControl { private TwitterSearchViewModel feedViewModel; public TwitterSearchView() { InitializeComponent(); this.Loaded += ResultsView_Loaded; } private void ResultsView_Loaded(object sender, RoutedEventArgs e) { feedViewModel = this.DataContext as TwitterSearchViewModel; // detect collection changed feedViewModel.Tweets.CollectionChanged += FeedItems_CollectionChanged; } private void FeedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { // manually 'refresh' the UI itemsControl.ItemsSource = null; itemsControl.ItemsSource = feedViewModel.Tweets; } } |
Conclusions
Creating a cross-platform WinRT / Silverlight application is entirely possible, using the same techniques that we currently employ for cross-platform Silverlight / WPF / WP7 applications. There are further complications relating to classes living in different namespaces and there will of course be other detail-level differences that this simple example does not touch upon. However, I think this presents a feasible and promising route for re-using existing Silverlight/ WPF code, and for developing applications that target the Win8 tablet, WP7 phone and Silverlight (or WPF) desktop with a single code-base.
You can download the full sourcecode: CrossPlatformTwitter.zip
Regards, Colin E.
Tags: cross-platform, silverlight, Windows 8, WinRT


email: ceberhardt@scottlogic.co.uk
on Google+



[...] Sharing code samples. Like this:LikeBe the first to like this. This entry was posted in .Net 4.0, .Net 4.5, Silverlight, WP, WPF, XAML. Bookmark the permalink. ← Async Targeting Pack for Visual Studio 2012 [...]
Great article. Thanks!
[...] TweetSearch – A Cross platform Metro UI WinRT and Silverlight Application (Colin Eberhardt) [...]
My expectation is that Visual Studio LightSwitch will have a “Metro/WinRT” output option that will make changes like the ones described in this article.
Really? Does it already have a WPF / Silverlight / WP7 output option? The problem is the detail level differences in each framework are numerous and hard to resolve. I guess LightSwitch has the advantage that it gives you a further abstraction layer.
Colin, GREAT article, thanks! I’m glad to see that you actually are using C#. It seems trendy (and completely ludicrous) that so many that are huge champions of the C# language are writing articles using javascript as their language of choice to target WinRT. I think this is causing mass confusion.
Art, why on earth would you want to convert your SL app to a metro app? Hopefully you don’t have Mac users to support, because if you do, converting your SL app to a metro app will force your Mac users to run Win8; good luck with that!
Colin, the images did not make it into the downloadable archive. Thanks.
Sorry – my bad. The images are not actually used by the application. I will fix it this morning.
I later realized that the metro project images were the default ones created for publishing. I copied them over from a new Metro project and built. Not sure about the one Silverlight image, but I had removed its usage prior to building. Thanks, Colin.
[...] Read original post by Colin Eberhardt at ScottLogic [...]
Great post.
Do you know if INavigationContentLoader will work in Metro for intra-application page changes?
Or MEF?
I work on a large LOB application (over 150 unique data entry forms) that makes extensive use of MEF for dynamic XAP download/integration. Even though there is no web server involved, it might make sense to be able to dynamically include only the modules that are needed at a particular time.
I also depend on Telerik’s Silverlight control suite so I won’t be trying a Metro port until they come out with Metro support.
Thanks
Regarding INavigationContentLoader – I doubt it, although you can check the current Metro App APIs here:
http://msdn.microsoft.com/en-us/library/windows/apps/br211369%28v=VS.85%29.aspx
MEF – again, I doubt it. Because of the market-place deployment model of Metro apps, MEF doesn’t really fit. The same is true of WP7. I do wonder whether Metro is the best place for LOB apps.
I don’t think data-entry gels with the Metro UI, for example, having played with Win8 on a desktop, little things are missing, for example,double-clicking on a block of text in a TextBox does not select the entire word. These little things make a bit difference in LOB apps.
I plan to learn as much as possible about WinRT, but only intend to start moving apps into this new world when I have decided they are right for it.
I am sure Telerik will bring out some Metro controls, they do everything else!