How different is WinRT really?

Update 29 February 2012: There is now a post covering the Consumer Preview/Beta changes: How different is Metro Style (WinRT) development really? The beta post

Note: Before you read this post, it is using the public technical preview of Windows 8, VS 11 & .NET 4.5, so I expect some issues will likely be resolved in later releases.

Recently, I have been working on an MVVM framework (it’s the new Hello World project for developers) and wanted to make sure it worked with WPF, Silverlight, and the new hotness: WinRT (or Metro or Windows 8, depending on who you ask). So I started to retrofit the framework and build a demo application at the same time to show it off. I quickly found a bunch of issues you need to take care of when moving to WinRT.

Namespaces

It has been mentioned since //Build that we will have new namespaces, so this should not be a surprise. In my MVVM framework, it looks like this:

#if WINRT
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Core;
    using Windows.UI.Xaml.Data;
#else
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Controls.Primitives;
    using System.ComponentModel;
#endif

You should be able to spot an almost one-to-one mapping there, except for the last few—but we’ll get to those.

Duplication of INotifyPropertyChanged, ICommand, & INotifyCollectionChanged

home-simpson-fire-cereal-epic-fail

This issue will affect every developer in WinRT, and it’s a massive fail on Microsoft’s part. The INotifyPropertyChanged, ICommand, and INotifyCollectionChanged interfaces—used in every XAML-based system—are not the same ones used in WinRT XAML-based systems. In fact, the framework has two of each—one in the old namespace and one in the new namespace. So your databinding will just break with no compiler errors! To fix this, you must switch the namespaces.

ObservableCollection<T> is broken

doublefacepalm

Hand in hand with the previous issue is that the trusted ObservableCollection<T> no longer works. It implements the old (and wrong) INotifyCollectionChanged, so all bindings to it are broken. You must bind to a class that implements IVector<T> instead. One problem: The framework doesn’t ship with an implementation! So to bind to collections, you need to build your own collection class or grab a shim (as I chose to).

Proxies & WebRequest

😊 😊 I used WebRequest in the demo to pull images from Flickr, and you know what just worked? Proxy settings. The first time ever in .NET! I hope whoever decided that proxies should just work gets an award! 😊 😊

Reflection has added a whole new layer

In non-WinRT, we can get all kinds of info on a type directly by working with that type (e.g., Type.GetType). However, in WinRT, that’s not the case! Type.GetType is no longer enough. Once you’ve gotten the type, you need to call GetTypeInfo() on it to retrieve all the information. Why this extra layer exists is beyond me.

#if WINRT
                if (control != null && typeof(ButtonBase).GetTypeInfo().IsAssignableFrom(control.GetType().GetTypeInfo()))
#else
#if SILVERLIGHT
                if (control != null && typeof(ButtonBase).IsAssignableFrom(control.GetType()))
#else
                if (control != null && control is ICommandSource)
#endif
#endif

MIA Types & Methods

For an MVVM framework, you’ll need a bit of reflection, so the first thing I noticed is that the super-handy Type.EmptyTypes is gone! So to get as close to a single codebase as possible, I’m now doing this nonsense:

🙁

#if WINRT
        private readonly Type[] EmptyTypes = new Type[] { };
#else
        private readonly Type[] EmptyTypes = Type.EmptyTypes;
#endif

There are a fair number of missing properties and methods—like Type.GetType lacking some of its beloved overloads:

#if WINRT
            var viewType = Type.GetType(viewName);
#else
            var viewType = Type.GetType(viewName, true, true);
#endif

Lastly, don’t expect familiar methods like GetConstructor, GetMethod, or GetProperty to exist. Now, we must work with collections we can iterate over. I admit it’s a better option, but some helper methods would’ve been useful.

public static MethodInfo GetMethod(this Type type, string methodName, Type[] parameters)
{
    var results = from m in type.GetTypeInfo().DeclaredMethods
                  where m.Name == methodName
                  let methodParameters = m.GetParameters().Select(_ => _.ParameterType).ToArray()
                  where methodParameters.Length == parameters.Length &&
                        !methodParameters.Except(parameters).Any() &&
                        !parameters.Except(methodParameters).Any()
                  select m;

    return results.FirstOrDefault();
}

So be aware: when working with reflection in WinRT, expect things to work differently.

User Controls must be created on the main thread!

This one I don’t understand at all. In WPF and Silverlight, a background thread can create a user control and pass the content to a Window on the main thread—a super useful feature for creating content and then popping it into the foreground almost instantly! However, WinRT has different ideas: all user controls must be created on the main thread—yuck!

#if WINRT
                Window.Current.Dispatcher.Invoke(CoreDispatcherPriority.High, (s, e) =>
                    {
#endif
                        shell = (IShell)typeof(TShell).GetConstructor(EmptyTypes).Invoke(null);
#if WINRT
                    }, this, null);
#endif

Simpson Fail Image from: http://www.thebuzzmedia.com/creator-of-wikipedia-fail-fast-fail-often/

Double face palm image from: http://tvtropes.org/pmwiki/pmwiki.php/Main/FacePalm