[WPF 4.5] Subscribing to an event using a markup extension


It’s been a while since I last wrote about markup extensions… The release of Visual Studio 11 Developer Preview, which introduces a number of new features to WPF, just gave me a reason to play with them again. The feature I’m going to discuss here is perhaps not the most impressive, but it fills in a gap of the previous versions: the support of markup extensions for events.

Until now, it was possible to use a markup extension in XAML to assign a value to a property, but we couldn’t do the same to subscribe to an event. In WPF 4.5, it is now possible. So here is a small example of the kind we can do with it…

When using the MVVM pattern, we often associate commands of the ViewModel with controls of the view, via the binding mechanism. This approach usually works well, but it has some downsides:

  • it introduces a lot of boilerplate code in the ViewModel
  • not all controls have a Command property (actually, most don’t), and when this property exists, it corresponds only to one event of the control (e.g. the click on a button). There is no really easy way to “bind” the other events to commands of the ViewModel

It would be nice to be able to bind events directly to ViewModel methods, like this:

        <Button Content="Click me"
                Click="{my:EventBinding OnClick}" />

With the OnClick method defined in the ViewModel:

        public void OnClick(object sender, EventArgs e)
        {
            MessageBox.Show("Hello world!");
        }

Well, this is now possible! Here’s a proof of concept… The EventBindingExtension class shown below first gets the DataContext of the control, then looks for the specified method on the DataContext, and eventually returns a delegate for this method:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;


    public class EventBindingExtension : MarkupExtension
    {
        public EventBindingExtension() { }

        public EventBindingExtension(string eventHandlerName)
        {
            this.EventHandlerName = eventHandlerName;
        }

        [ConstructorArgument("eventHandlerName")]
        public string EventHandlerName { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (string.IsNullOrEmpty(EventHandlerName))
                throw new ArgumentException("The EventHandlerName property is not set", "EventHandlerName");

            var target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));

            EventInfo eventInfo = target.TargetProperty as EventInfo;
            if (eventInfo == null)
                throw new InvalidOperationException("The target property must be an event");
            
            object dataContext = GetDataContext(target.TargetObject);
            if (dataContext == null)
                throw new InvalidOperationException("No DataContext found");

            var handler = GetHandler(dataContext, eventInfo, EventHandlerName);
            if (handler == null)
                throw new ArgumentException("No valid event handler was found", "EventHandlerName");

            return handler;
        }

        #region Helper methods

        static object GetHandler(object dataContext, EventInfo eventInfo, string eventHandlerName)
        {
            Type dcType = dataContext.GetType();

            var method = dcType.GetMethod(
                eventHandlerName,
                GetParameterTypes(eventInfo));
            if (method != null)
            {
                if (method.IsStatic)
                    return Delegate.CreateDelegate(eventInfo.EventHandlerType, method);
                else
                    return Delegate.CreateDelegate(eventInfo.EventHandlerType, dataContext, method);
            }

            return null;
        }

        static Type[] GetParameterTypes(EventInfo eventInfo)
        {
            var invokeMethod = eventInfo.EventHandlerType.GetMethod("Invoke");
            return invokeMethod.GetParameters().Select(p => p.ParameterType).ToArray();
        }

        static object GetDataContext(object target)
        {
            var depObj = target as DependencyObject;
            if (depObj == null)
                return null;

            return depObj.GetValue(FrameworkElement.DataContextProperty)
                ?? depObj.GetValue(FrameworkContentElement.DataContextProperty);
        }

        #endregion
    }

This class can be used as shown in the example above.

As it is now, this markup extension has an annoying limitation: the DataContext must be set before the call to ProvideValue, otherwise it won’t be possible to find the event handler method. A solution could be to subscribe to the DataContextChanged event to look for the method after the DataContext is set, but in the meantime we still need to return something… and we can’t return null, because it would cause an exception (since you can’t subscribe to an event with a null handler). So we need to return a dummy handler generated dynamically from the event signature. It makes things a bit harder… but it’s still feasible.

Here’s a second version that implements this improvement :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Windows;
using System.Windows.Markup;

    public class EventBindingExtension : MarkupExtension
    {
        private EventInfo _eventInfo;

        public EventBindingExtension() { }

        public EventBindingExtension(string eventHandlerName)
        {
            this.EventHandlerName = eventHandlerName;
        }

        [ConstructorArgument("eventHandlerName")]
        public string EventHandlerName { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (string.IsNullOrEmpty(EventHandlerName))
                throw new ArgumentException("The EventHandlerName property is not set", "EventHandlerName");

            var target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));

            var targetObj = target.TargetObject as DependencyObject;
            if (targetObj == null)
                throw new InvalidOperationException("The target object must be a DependencyObject");

            _eventInfo = target.TargetProperty as EventInfo;
            if (_eventInfo == null)
                throw new InvalidOperationException("The target property must be an event");

            object dataContext = GetDataContext(targetObj);
            if (dataContext == null)
            {
                SubscribeToDataContextChanged(targetObj);
                return GetDummyHandler(_eventInfo.EventHandlerType);
            }

            var handler = GetHandler(dataContext, _eventInfo, EventHandlerName);
            if (handler == null)
            {
                Trace.TraceError(
                    "EventBinding: no suitable method named '{0}' found in type '{1}' to handle event '{2'}",
                    EventHandlerName,
                    dataContext.GetType(),
                    _eventInfo);
                return GetDummyHandler(_eventInfo.EventHandlerType);
            }

            return handler;
            
        }

        #region Helper methods

        static Delegate GetHandler(object dataContext, EventInfo eventInfo, string eventHandlerName)
        {
            Type dcType = dataContext.GetType();

            var method = dcType.GetMethod(
                eventHandlerName,
                GetParameterTypes(eventInfo.EventHandlerType));
            if (method != null)
            {
                if (method.IsStatic)
                    return Delegate.CreateDelegate(eventInfo.EventHandlerType, method);
                else
                    return Delegate.CreateDelegate(eventInfo.EventHandlerType, dataContext, method);
            }

            return null;
        }

        static Type[] GetParameterTypes(Type delegateType)
        {
            var invokeMethod = delegateType.GetMethod("Invoke");
            return invokeMethod.GetParameters().Select(p => p.ParameterType).ToArray();
        }

        static object GetDataContext(DependencyObject target)
        {
            return target.GetValue(FrameworkElement.DataContextProperty)
                ?? target.GetValue(FrameworkContentElement.DataContextProperty);
        }

        static readonly Dictionary<Type, Delegate> _dummyHandlers = new Dictionary<Type, Delegate>();

        static Delegate GetDummyHandler(Type eventHandlerType)
        {
            Delegate handler;
            if (!_dummyHandlers.TryGetValue(eventHandlerType, out handler))
            {
                handler = CreateDummyHandler(eventHandlerType);
                _dummyHandlers[eventHandlerType] = handler;
            }
            return handler;
        }

        static Delegate CreateDummyHandler(Type eventHandlerType)
        {
            var parameterTypes = GetParameterTypes(eventHandlerType);
            var returnType = eventHandlerType.GetMethod("Invoke").ReturnType;
            var dm = new DynamicMethod("DummyHandler", returnType, parameterTypes);
            var il = dm.GetILGenerator();
            if (returnType != typeof(void))
            {
                if (returnType.IsValueType)
                {
                    var local = il.DeclareLocal(returnType);
                    il.Emit(OpCodes.Ldloca_S, local);
                    il.Emit(OpCodes.Initobj, returnType);
                    il.Emit(OpCodes.Ldloc_0);
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }
            }
            il.Emit(OpCodes.Ret);
            return dm.CreateDelegate(eventHandlerType);
        }

        private void SubscribeToDataContextChanged(DependencyObject targetObj)
        {
            DependencyPropertyDescriptor
                .FromProperty(FrameworkElement.DataContextProperty, targetObj.GetType())
                .AddValueChanged(targetObj, TargetObject_DataContextChanged);
        }

        private void UnsubscribeFromDataContextChanged(DependencyObject targetObj)
        {
            DependencyPropertyDescriptor
                .FromProperty(FrameworkElement.DataContextProperty, targetObj.GetType())
                .RemoveValueChanged(targetObj, TargetObject_DataContextChanged);
        }

        private void TargetObject_DataContextChanged(object sender, EventArgs e)
        {
            DependencyObject targetObj = sender as DependencyObject;
            if (targetObj == null)
                return;

            object dataContext = GetDataContext(targetObj);
            if (dataContext == null)
                return;

            var handler = GetHandler(dataContext, _eventInfo, EventHandlerName);
            if (handler != null)
            {
                _eventInfo.AddEventHandler(targetObj, handler);
            }
            UnsubscribeFromDataContextChanged(targetObj);
        }

        #endregion
    }

So this is the kind of things we can do thanks to this new WPF feature. We could also imagine a behavior system similar to what we can do with attached properties, e.g. to execute a standard action when an event occurs. There are lots of possible applications for this, I leave it to you to find them ;)

kick it on DotNetKicks.com

[WPF] Markup extensions and templates


Note : This post follows the one about a a markup extension that can update its target, and reuses the same code.

You may have noticed that using a custom markup extension in a template sometimes lead to unexpected results… In this post I’ll explain what the problem is, and how to create a markup extensions that behaves correctly in a template.

The problem

Let’s take the example from the previous post : a markup extension which gives the state of network connectivity, and updates its target when the network is connected or disconnected :

<CheckBox IsChecked="{my:NetworkAvailable}" Content="Network is available" />

Now let’s put the same CheckBox in a ControlTemplate :

<ControlTemplate x:Key="test">
  <CheckBox IsChecked="{my:NetworkAvailable}" Content="Network is available" />
</ControlTemplate>

And let’s create a control which uses this template :

<Control Template="{StaticResource test}" />

If we disconnect from the network, we notice that the CheckBox is not automatically updated by the NetworkAvailableExtension, whereas it was working fine when we used it outside the template…

Explanation and solution

The markup expression is evaluated when it is encountered by the XAML parser : in that case, when the template is parsed. But at this time, the CheckBox control is not created yet, so the ProvideValue method can’t access it… When a markup extension is evaluated inside a template, the TargetObject is actually an instance of System.Windows.SharedDp, an internal WPF class.

For the markup extension to be able to access its target, it has to be evaluated when the template is applied : we need to defer its evaluation until this time. It’s actually pretty simple, we just need to return the markup extension itself from ProvideValue : this way, it will be evaluated again when the actual target control is created.

To check if the extension is evaluated for the template or for a “real” control, we just need to test whether the type of the TargetObject is System.Windows.SharedDp. So the code of the ProvideValue method becomes :

        public sealed override object ProvideValue(IServiceProvider serviceProvider)
        {
            IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
            if (target != null)
            {
                if (target.TargetObject.GetType().FullName == "System.Windows.SharedDp")
                    return this;
                _targetObject = target.TargetObject;
                _targetProperty = target.TargetProperty;
            }

            return ProvideValueInternal(serviceProvider);
        }

Cool, it’s now fixed, the CheckBox is updated when the network connectivity changes :)

Last, but not least

OK, we have a solution that apparently works fine, but let’s not count our chickens before they’re hatched… What if we now want to use our ControlTemplate on several controls ?

<Control Template="{StaticResource test}" />
<Control Template="{StaticResource test}" />

Now let’s run the application and unplug the network cable : the second CheckBox is updated, but the first one is not…

The reason for this is simple : there are two CheckBox controls, but only one instance of NetworkAvailableExtension, shared between all instances of the template. Now, NetworkAvailableExtension can only reference one target object, so only the last one for which ProvideValue has been called is kept…

So we need to keep track of not one target object, but a collection of target objects, which will all be update by the UpdateValue method. Here’s the final code of the UpdatableMarkupExtension base class :

    public abstract class UpdatableMarkupExtension : MarkupExtension
    {
        private List<object> _targetObjects = new List<object>();
        private object _targetProperty;

        protected IEnumerable<object> TargetObjects
        {
            get { return _targetObjects; }
        }

        protected object TargetProperty
        {
            get { return _targetProperty; }
        }

        public sealed override object ProvideValue(IServiceProvider serviceProvider)
        {
            // Retrieve target information
            IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

            if (target != null && target.TargetObject != null)
            {
                // In a template the TargetObject is a SharedDp (internal WPF class)
                // In that case, the markup extension itself is returned to be re-evaluated later
                if (target.TargetObject.GetType().FullName == "System.Windows.SharedDp")
                    return this;

                // Save target information for later updates
                _targetObjects.Add(target.TargetObject);
                _targetProperty = target.TargetProperty;
            }

            // Delegate the work to the derived class
            return ProvideValueInternal(serviceProvider);
        }

        protected virtual void UpdateValue(object value)
        {
            if (_targetObjects.Count > 0)
            {
                // Update the target property of each target object
                foreach (var target in _targetObjects)
                {
                    if (_targetProperty is DependencyProperty)
                    {
                        DependencyObject obj = target as DependencyObject;
                        DependencyProperty prop = _targetProperty as DependencyProperty;

                        Action updateAction = () => obj.SetValue(prop, value);

                        // Check whether the target object can be accessed from the
                        // current thread, and use Dispatcher.Invoke if it can't

                        if (obj.CheckAccess())
                            updateAction();
                        else
                            obj.Dispatcher.Invoke(updateAction);
                    }
                    else // _targetProperty is PropertyInfo
                    {
                        PropertyInfo prop = _targetProperty as PropertyInfo;
                        prop.SetValue(target, value, null);
                    }
                }
            }
        }

        protected abstract object ProvideValueInternal(IServiceProvider serviceProvider);
    }

The UpdatableMarkupExtension is now fully functional… until proved otherwise ;). This class makes a good starting point for any markup extension that needs to update its target, without having to worry about the low-level aspects of tracking and updating target objects.

[WPF] A markup extension that can update its target


If you have read my previous posts on the topic, you know I’m a big fan of custom markup extensions… However, they have a limitation that can be quite annoying : they are only evaluated once. Yet it would be useful to be able to evaluate them again to update the target property, like a binding… It could be useful in various cases, for instance :

  • if the value of the markup extension can change in response to an event
  • if the state of the target object when the markup extension is evaluated doesn’t allow to determine the value yet, and the evaluation needs to be deferred (for instance, if the DataContext of the target object is needed, but is not yet defined when the markup extension is evaluated)

This post explains how to update the target of a markup extension after the initial evaluation.

The ProvideValue method of a markup extension takes a parameter of type IServiceProvider, which provides, among others, a IProvideValueTarget service. This interface exposes two properties, TargetObject and TargetProperty, which allow to retrieve the target object and property of the markup extension. It is then possible, if you retain this information, to update the property after the markup extension has already been evaluated.

To carry out this task, we can create an abstract class UpdatableMarkupExtension, which saves the target object and property, and provides a method to update the value :

    public abstract class UpdatableMarkupExtension : MarkupExtension
    {
        private object _targetObject;
        private object _targetProperty;

        protected object TargetObject
        {
            get { return _targetObject; }
        }

        protected object TargetProperty
        {
            get { return _targetProperty; }
        }

        public sealed override object ProvideValue(IServiceProvider serviceProvider)
        {
            IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
            if (target != null)
            {
                _targetObject = target.TargetObject;
                _targetProperty = target.TargetProperty;
            }

            return ProvideValueInternal(serviceProvider);
        }

        protected void UpdateValue(object value)
        {
            if (_targetObject != null)
            {
                if (_targetProperty is DependencyProperty)
                {
                    DependencyObject obj = _targetObject as DependencyObject;
                    DependencyProperty prop = _targetProperty as DependencyProperty;

                    Action updateAction = () =>  obj.SetValue(prop, value);

                    // Check whether the target object can be accessed from the
                    // current thread, and use Dispatcher.Invoke if it can't

                    if (obj.CheckAccess())
                        updateAction();
                    else
                        obj.Dispatcher.Invoke(updateAction);
                }
                else // _targetProperty is PropertyInfo
                {
                    PropertyInfo prop = _targetProperty as PropertyInfo;
                    prop.SetValue(_targetObject, value, null);
                }
            }
        }

        protected abstract object ProvideValueInternal(IServiceProvider serviceProvider);
    }

Since it is essential that the target object and property are saved, we mark the ProvideValue method as sealed so that it cannot be overriden, and we add an abstract ProvideValueInternal method so that inheritors can provide their implementation.

The UpdateValue method handles the update of the target property, which can be either a dependency property (DependencyProperty), or a standard CLR property (PropertyInfo). In the case of a DependencyProperty, the target object inherits from DependencyObject, which itself inherits from DispatcherObject : it is therefore necessary to make sure that the object is only accessed from the thread that owns it, using the CheckAccess and Invoke methods.

Here’s a simple example to illustrate how to use this class. Let’s assume we want to create a custom markup extension which indicates whether the network is available. It would be used like that :

<CheckBox IsChecked="{my:NetworkAvailable}" Content="Network is available" />

Obviously, we want the checkbox to be updated when the availability of the network changes (e.g. when the network cable is plugged or unplugged, or when the Wifi network is out of reach). So we need to handle the NetworkChange.NetworkAvailabilityChanged event, and update the IsChecked property accordingly. So the extension will inherit the UpdatableMarkupExtension class to take advantage of the UpdateValue method :

    public class NetworkAvailableExtension : UpdatableMarkupExtension
    {
        public NetworkAvailableExtension()
        {
            NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
        }

        protected override object ProvideValueInternal(IServiceProvider serviceProvider)
        {
            return NetworkInterface.GetIsNetworkAvailable();
        }

        private void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
        {
            UpdateValue(e.IsAvailable);
        }
    }

Note that we subscribe to the NetworkAvailabilityChanged event in the class constructor. If we wanted to subscribe to an event of the target object, we would have to do it in the ProvideValueInternal method, so that the target object can be accessed.

I hope this post let you see how simple it is to implement a markup extension that can update its target at a later time. This enables a behavior similar to a binding, but is not limited to dependency properties. An example of where I use this technique is to create a localization framework that allows to switch language “on the fly”, without restarting the application.

Update :
In its current state, this markup extension can’t be used in a template. For an explanation and a solution to that issue, please read this post.

[WPF] Using InputBindings with the MVVM pattern


If you develop WPF applications according to the Model-View-ViewModel pattern, you may have faced this issue : in XAML, how to bind a key or mouse gesture to a ViewModel command ? The obvious and intuitive approach would be this one :

    <UserControl.InputBindings>
        <KeyBinding Modifiers="Control" Key="E" Command="{Binding EditCommand}"/>
    </UserControl.InputBindings>

Unfortunately, this code doesn’t work, for two reasons :

  1. The Command property is not a dependency property, so you cannot assign it through binding
  2. InputBindings are not part of the logical or visual tree of the control, so they don’t inherit the DataContext

A solution would be to create the InputBindings in the code-behind, but in the MVVM pattern we usually prefer to avoid this… I spent a long time looking for alternative solutions to do this in XAML, but most of them are quite complex and unintuitive. So I eventually came up with a markup extension that enables binding to ViewModel commands, anywhere in XAML, even for non-dependency properties or if the element doesn’t normally inherit the DataContext

This extension is used like a regular binding :

    <UserControl.InputBindings>
        <KeyBinding Modifiers="Control" Key="E" Command="{input:CommandBinding EditCommand}"/>
    </UserControl.InputBindings>

(The input XML namespace is mapped to the CLR namespace where the markup extension is declared)

In order to write this extension, I had to cheat a little… I used Reflector to find some private fields that would allow to retrieve the DataContext of the root element. I then accessed those fields using reflection.

Here is the code of the markup extension :

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;

namespace MVVMLib.Input
{
    [MarkupExtensionReturnType(typeof(ICommand))]
    public class CommandBindingExtension : MarkupExtension
    {
        public CommandBindingExtension()
        {
        }

        public CommandBindingExtension(string commandName)
        {
            this.CommandName = commandName;
        }

        [ConstructorArgument("commandName")]
        public string CommandName { get; set; }

        private object targetObject;
        private object targetProperty;

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
            if (provideValueTarget != null)
            {
                targetObject = provideValueTarget.TargetObject;
                targetProperty = provideValueTarget.TargetProperty;
            }

            if (!string.IsNullOrEmpty(CommandName))
            {
                // The serviceProvider is actually a ProvideValueServiceProvider, which has a private field "_context" of type ParserContext
                ParserContext parserContext = GetPrivateFieldValue<ParserContext>(serviceProvider, "_context");
                if (parserContext != null)
                {
                    // A ParserContext has a private field "_rootElement", which returns the root element of the XAML file
                    FrameworkElement rootElement = GetPrivateFieldValue<FrameworkElement>(parserContext, "_rootElement");
                    if (rootElement != null)
                    {
                        // Now we can retrieve the DataContext
                        object dataContext = rootElement.DataContext;

                        // The DataContext may not be set yet when the FrameworkElement is first created, and it may change afterwards,
                        // so we handle the DataContextChanged event to update the Command when needed
                        if (!dataContextChangeHandlerSet)
                        {
                            rootElement.DataContextChanged += new DependencyPropertyChangedEventHandler(rootElement_DataContextChanged);
                            dataContextChangeHandlerSet = true;
                        }

                        if (dataContext != null)
                        {
                            ICommand command = GetCommand(dataContext, CommandName);
                            if (command != null)
                                return command;
                        }
                    }
                }
            }

            // The Command property of an InputBinding cannot be null, so we return a dummy extension instead
            return DummyCommand.Instance;
        }

        private ICommand GetCommand(object dataContext, string commandName)
        {
            PropertyInfo prop = dataContext.GetType().GetProperty(commandName);
            if (prop != null)
            {
                ICommand command = prop.GetValue(dataContext, null) as ICommand;
                if (command != null)
                    return command;
            }
            return null;
        }

        private void AssignCommand(ICommand command)
        {
            if (targetObject != null && targetProperty != null)
            {
                if (targetProperty is DependencyProperty)
                {
                    DependencyObject depObj = targetObject as DependencyObject;
                    DependencyProperty depProp = targetProperty as DependencyProperty;
                    depObj.SetValue(depProp, command);
                }
                else
                {
                    PropertyInfo prop = targetProperty as PropertyInfo;
                    prop.SetValue(targetObject, command, null);
                }
            }
        }

        private bool dataContextChangeHandlerSet = false;
        private void rootElement_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement rootElement = sender as FrameworkElement;
            if (rootElement != null)
            {
                object dataContext = rootElement.DataContext;
                if (dataContext != null)
                {
                    ICommand command = GetCommand(dataContext, CommandName);
                    if (command != null)
                    {
                        AssignCommand(command);
                    }
                }
            }
        }

        private T GetPrivateFieldValue<T>(object target, string fieldName)
        {
            FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
            if (field != null)
            {
                return (T)field.GetValue(target);
            }
            return default(T);
        }

        // A dummy command that does nothing...
        private class DummyCommand : ICommand
        {

            #region Singleton pattern

            private DummyCommand()
            {
            }

            private static DummyCommand _instance = null;
            public static DummyCommand Instance
            {
                get
                {
                    if (_instance == null)
                    {
                        _instance = new DummyCommand();
                    }
                    return _instance;
                }
            }

            #endregion

            #region ICommand Members

            public bool CanExecute(object parameter)
            {
                return false;
            }

            public event EventHandler CanExecuteChanged;

            public void Execute(object parameter)
            {
            }

            #endregion
        }
    }
}

However this solution has a limitation : it works only for the DataContext of the XAML root. So you can’t use it, for instance, to define an InputBinding on a control whose DataContext is also redefined, because the markup extension will access the root DataContext. It shouldn’t be a problem in most cases, but you need to be aware of that…

[WPF] Binding to application settings using a markup extension


Hi, this is my first post on this blog, I hope you will enjoy it ;-). If you want to know a few things about me, please check out this page.

The end-user of any application expects that his preferences (window size, state of this or that option…) are saved to be restored at the next run : that’s why .NET 2.0 introduced application settings as a unified way to persist these settings. However, if there are many settings, it can be a real hassle for the developper to handle them… even with the help of the Settings class generated by Visual Studio, there is still quite a lot of code to write to apply these settings to the user interface, then update them according to user modifications.

In Windows Forms, it was possible to define bindings between control properties and application settings, but it wasn’t very intuitive, and wasn’t very widely used (I’m not so sure about that, but I actually never saw it used by anyone…).

With WPF, we can do something similar in a much more elegant way… although it’s not “officially” documented, it is possible to create bindings to application settings in XAML. For instance, to persist the window size and position in application settings, many blogs suggest this approach :

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:p="clr-namespace:WpfApplication1.Properties"
        Title="Window1"
        Height="{Binding Source={x:Static p:Settings.Default}, Path=Height, Mode=TwoWay}"
        Width="{Binding Source={x:Static p:Settings.Default}, Path=Width, Mode=TwoWay}"
        Left="{Binding Source={x:Static p:Settings.Default}, Path=Left, Mode=TwoWay}"
        Top="{Binding Source={x:Static p:Settings.Default}, Path=Top, Mode=TwoWay}">

(In that example, Height, Width, Top and Left are application settings)

This code does work, but honestly, do you feel like writing this for every setting of the application ? It’s too verbose, not intuitive, and makes the code harder to read…

Of course, I’m not saying this idea is bad… but it’s very easy to improve it, by creating our own « markup extension ». In this post I’m going to explain how to write a class that inherits Binding, and allows to bind easily to application settings.

« Markup extension » are objects that can be used in XAML to retrieve values. They are used all the time in WPF : for instance, Binding, StaticResource and DynamicResource are markup extensions.

It’s quite easy to define your own markup extension, by creating a class that inherits the abstract MarkupExtension class, and implements the ProvideValue method. In our case, most of what we need is already implemented in the Binding class (which indirectly inherits MarkupExtension). So we’re just going to inherit Binding, and initialize the necessary properties in order to bind to application settings :

using System.Windows.Data;

namespace WpfApplication1
{
    public class SettingBindingExtension : Binding
    {
        public SettingBindingExtension()
        {
            Initialize();
        }

        public SettingBindingExtension(string path)
            :base(path)
        {
            Initialize();
        }

        private void Initialize()
        {
            this.Source = WpfApplication1.Properties.Settings.Default;
            this.Mode = BindingMode.TwoWay;
        }
    }
}

Note the « Extension » suffix at the end of the class name : by convention, most markup extensions have this suffix (Binding is an exception…). It can be omitted when using the class in XAML (similarly to attributes, for which the « Attribute » suffix can be omitted).

In that class, we defined two constructors, matching those of the Binding class. We don’t need to redefine the ProvideValue method, because the one implemented in the Binding class suits us perfectly (and anyway it is marked as sealed, so we couldn’t override it even if we wanted to…). The part that actually makes the code work is the Initialize method. It initializes the Source property, so that the Path of the binding maps to the specified setting, and sets Mode to TwoWay so that application settings are automatically updated from the UI. The point of doing this is that we don’t have to set these properties every time we bind to a setting…

To illustrate the usage of this markup extension, let’s go back to the previous example, and replace the Bindings with the SettingBinding extension :

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplication1"
        Title="Window1"
        Height="{my:SettingBinding Height}"
        Width="{my:SettingBinding Width}"
        Left="{my:SettingBinding Left}"
        Top="{my:SettingBinding Top}">

Isn’t it much clearer, more readable, and shorter to write ?

And of course, to make it work, let’s not forget to save the settings in the application’s Exit event…

        private void Application_Exit(object sender, ExitEventArgs e)
        {
            WpfApplication1.Properties.Settings.Default.Save();
        }

That’s it ! the window size and position are now saved, and restored when the application is started again, without having to write anything more…

Download source code

Update : If you understand French and want to know more about markup extensions, I suggest you read my tutorial on this topic : Les markup extensions en WPF

Follow

Get every new post delivered to your Inbox.