Tuesday, 26 June 2012

Binding To Event At Runtime In Windows 8 Metro

So I wanted to use the MVVM pattern in Win8 Metro WPF, but was without the classes and functionality I would use in WPF4. So I decided to create my own, but I got the error:

Adding or removing event handlers dynamically is not supported on WinRT events.

I found a blog post on the MSDN where some guy posted about using the WindowsRuntimeMarshal to get around that, but he didn't post a code sample. So, I decided to figure it out, and let everyone know!

So here's the code:

var eventName = "Click";
var myButton = new Button();
var runtimeEvent = myButton.GetType().GetRuntimeEvent(eventName);
var handlerType = runtimeEvent.EventHandlerType;
Func<RoutedEventHandler, EventRegistrationToken> add = (a) => { return (EventRegistrationToken)runtimeEvent.AddMethod.Invoke(myButton, new object[] { a }); };
Action<EventRegistrationToken> remove = (a) => { runtimeEvent.RemoveMethod.Invoke(runtimeEvent, new object[] { a }); };
RoutedEventHandler handler = (a, b) => Command.Execute(b);
WindowsRuntimeMarshal.AddEventHandler<RoutedEventHandler>(add, remove, handler);

So that's how we can add an event handler to an event at runtime in WinRT. Pretty simple, really. The one limitation of this code is that if you are trying to bind to an event that isn't a RoutedEvent, you're going to have to re-do the code. But I'm sure this is able to become a generic function with a little bit more work.