Markup Extensions for Events<\/em>“.<\/strong><\/p>\n<\/p>\n
What is it and what scenario it addresses ?<\/h3>\n
\nAs point out by Rob, markup extension can now provide values for event in the XAML. In this case, this is a Delegate which has to be provided. The WPF framework by itself does not define a markup extension to be used for events.<\/p>\n
This feature enable new scenario which will, in my opinion, step on the Blend behaviors toes. Indeed, to be able to create this kind of markup extension is a dream for someone which want to trigger an action on a control when an event is raised. Instead of remember which namespace to add and which behavior to use with which trigger a developer will just have to create a markup extension just like he would create a converter.<\/p>\n
Of course there is a drawback, a major one: this is not supported by Blend. If you are as a fan of Blend as I am, you’ll continue to use behavior\/triggers because it’s simply a drag & drop ahead !<\/p>\n
So even if, in my opinion it won’t be over-used, this is still a great feature and an option to keep in mind.<\/p>\n
How to use it ?<\/h3>\n
This time, it is not as obvious to uses as the other new features of WPF 4.5.<\/p>\n
To be a MarkupExtension, a class have to inherit from MarkupExtesion and to implement the abstract ProvideValue <\/em>method. It is called by the framework which provide an IServiceProvider object as a parameter.<\/p>\nThis serviceProvider is a dependency resolver which you can use to retrieve a service named IProvideValueTarget<\/em>. This one will then be used to obtain the property targeted by the MarkupExtension(you can get the Targeted object too with it). <\/p>\nThis property is the Event’s accessor (the one which is called when you subscribe to it with the ‘+=’ syntax). Then, reflection has to be used to find the Type of the handler of the aimed event.<\/p>\n
Once this is done, a Delegate can be created and returned as a provided value by this MarkupExtension. In the example below, the delegate handler is a method named ‘MyMarkupExtensionInternalHandler’ defined on the MarkupExtension itself. <\/p>\n
[csharp]public override object ProvideValue(IServiceProvider serviceProvider)
\n{
\n IProvideValueTarget targetProvider = serviceProvider
\n .GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
\n if (targetProvider == null)
\n throw new InvalidOperationException(@"The CallAction extension
\n\t can’t retrieved the IProvideValueTarget service.");<\/p>\n
var targetEventAddMethod = targetProvider.TargetProperty as MethodInfo;<\/p>\n
\/\/Retrieve the handler of the event
\n ParameterInfo[] pars = targetEventAddMethod.GetParameters();
\n Type delegateType = pars[1].ParameterType;<\/p>\n
\/\/Retrieves the method info of the proxy handler
\n MethodInfo methodInfo = this.GetType()
\n .GetMethod("MyMarkupExtensionInternalHandler",
\n BindingFlags.NonPublic | BindingFlags.Instance);<\/p>\n
\/\/Create a delegate to the proxy handler on the markupExtension
\n Delegate returnedDelegate = Delegate
\n .CreateDelegate(delegateType, this, methodInfo);<\/p>\n
return returnedDelegate;
\n}<\/p>\n
void MyMarkupExtensionInternalHandler(object sender, EventArgs e)
\n{
\n\t\t\/\/here something can be performed.
\n}[\/csharp]<\/p>\n
A few good things to know when you create your own markup extensions:<\/p>\n
\n- throw InvalidOperationException when something bad happens,<\/li>\n
- don’t think that everything is initialized: it is not. This is especially true for the DataContext of the target,<\/li>\n
- always checks that the objects you retrieve are not null especially the service obtained via the IServiceProvider argument.<\/li>\n<\/ol>\n
More advanced example<\/h3>\n
I wanted to write a full example when I played with this feature yesterday but I found out it could be a post by itself. So if you want a full example, you can read this post describing how to invoke a method on the ViewModel \/ DataContext when an event is raised<\/em><\/a>.;<\/p>\nRegards,<\/p>\n","protected":false},"excerpt":{"rendered":"
The first time I read about this new feature and its description, I just shake my head and thought : “what is this ?”! Then Rob Relyea, the ex-PM of the WPF team and Fabien…<\/p>\n","protected":false},"author":3,"featured_media":510,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4,5],"tags":[14,15],"_links":{"self":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts\/470"}],"collection":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/comments?post=470"}],"version-history":[{"count":33,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts\/470\/revisions"}],"predecessor-version":[{"id":524,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts\/470\/revisions\/524"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/media\/510"}],"wp:attachment":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/media?parent=470"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/categories?post=470"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/tags?post=470"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}