Update 29 Feb 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. Check the site out for more info!
Recently I have been working on a MVVM framework (it’s the new Hello World project for developers) and I wanted to make sure it worked with WPF, Silverlight & 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 that 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 almost a one to one mapping there, except for the last few, but we will get to those.
Duplication of INotifyPropertyChanged, ICommand & INotifyCollectionChanged
This issue will affect EVERY developer in WinRT and it is a MASSIVE fail on Microsoft’s part. The INotifyPropertyChanged, ICommand & INotifyCollectionChanged that are used in every XAML based system are not the 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 you will find your databinding just broken with no compiler errors! To solve this you have to switch the namespaces.
ObservableCollection<T> is broken
Hand in hand with the previous one is that the trusted ObservableCollection<T> no longer works either! It implements the old (wrong INotifyCollectionChanged) and thus all bindings to it are broken. You need to bind to a class that implements IVectorCollection<T>. 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 who ever 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 (i.e. Type.GetType). However in WinRT that is not the case! Type.GetType is no longer enough, when you have gotten the type you need to call GetTypeInfo on that to get to all the information on the type. Why this extra layer is here 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 a MVVM framework you will have a bit of reflection and so the first thing I noticed is the super handy Types.EmptyTypes is gone! So to have as close to a single code base I am doing this nonsense now
#if (WINRT) private readonly Type[] EmptyTypes = new Type[] { }; #else private readonly Type[] EmptyTypes = Type.EmptyTypes; #endif
There is a fair bit of these missing properties & methods like Type.GetType is missing some of the overloads I have come to love:
#if WINRT var viewType = Type.GetType(viewName); #else var viewType = Type.GetType(viewName, true, true); #endif
Lastly do not expect the trusted methods like GetConstructor, GetMethod or GetProperty to exist. Now we have collections we can iterate over. I admit this is a better option, but some helper methods here 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 in reflection be aware that it will work differently.
User Controls must be created on the main thread!
This I do not get at all, but in WPF & Silverlight a background thread can create a user control and pass the content to a Window on the main thread. This is SUPER useful for the creation of content and then when needing 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