[VS2010] Binding support in InputBindings

Very poorPoorAverageGoodExcellent (2 votes) 
Loading ... Loading ...

THE feature that was missing from WPF !

Visual Studio 2010 beta 2 has been released last week, and it brings to WPF a long awaited feature : support for bindings in InputBindings.

As a reminder, the issue in previous releases was that the Command property of the InputBinding class wasn’t a DependencyProperty, so it wasn’t possible to bind it. Furthermore, InputBindings didn’t inherit the parent DataContext, which made it difficult to provide alternative implementations…

Until now, in order to bind the Command of a KeyBinding or MouseBinding to a property of the DataContext, we had to resort to clumsy workarounds… I had eventually came up with an acceptable solution, described in this post, but I wasn’t really satisfied with it (it used reflection on private members, and had annoying limitations).

More recently, I found a better solution in the MVVM toolkit : a CommandReference class, inherited from Freezable, allows to put a reference to a ViewModel command in the page or control resources, so that it can be used later with StaticResource. It’s much cleaner than my previous solution, but still not very straightforward…

WPF 4.0 solves that problem once and for all : the InputBinding class now inherits from Freezable, which allows it to inherit the DataContext, and the Command, CommandParameter and CommandTarget properties are now dependency properties. So, at last, we can forget about the clumsy workarounds described above, and go straight to the point :

    <Window.InputBindings>
        <KeyBinding Key="F5"
                    Command="{Binding RefreshCommand}" />
    </Window.InputBindings>

This new feature should make it much easier to develop MVVM applications !

Help 3

Other than that, I would like to say a few words about the new offline help system that comes with Visual Studio 2010, called “Help 3″. It’s quite a big change compared to previous versions… First, it’s not a standalone application anymore, but a locally hosted web application, so you can access the documentation with your favorite web browser. On the whole, it’s better than the previous system… much faster and more responsive than the old Document Explorer included in previous Visual Studio releases.

However, the new system misses the feature that was the most useful to me : the index ! Now there’s only the hierarchical view, and a search textbox. IMHO, the index was the most convenient way of looking up something in the doc, it made it very easy to access a class or member directly, even without knowing its namespace… why on earth did they remove it ? Worse still : the search results don’t show the namespace, only the class or member name. For instance, if you search “button class”, in the results there is no way to see the difference between System.Windows.Forms.Button, System.Windows.Controls.Button and System.Web.UI.WebControls ! You have to click each link and see where it leads… In Document Explorer, the Index Results pane showed this information clearly.

So, eventually I have mixed feelings about this new help system, because I will have to change the way I use the documentation. But except for this annoying detail, I must concede that it’s objectively a big improvement over the old system…

[WPF] Binding to an asynchronous collection

Very poorPoorAverageGoodExcellent (18 votes) 
Loading ... Loading ...

As you may have noticed, it is not possible to modify the contents of an ObservableCollection on a separate thread if a view is bound to this collection : the CollectionView raises a NotSupportedException :

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread

To illustrate this, let’s take a simple example : a ListBox bound to a collection of strings in the ViewModel :

        private ObservableCollection<string> _strings = new ObservableCollection<string>();
        public ObservableCollection<string> Strings
        {
            get { return _strings; }
            set
            {
                _strings = value;
                OnPropertyChanged("Strings");
            }
        }
    <ListBox ItemsSource="{Binding Strings}"/>

If we add items to this collection out of the main thread, we get the exception mentioned above. A possible solution would be to create a new collection, and assign it to the Strings property when it is filled, but in this case the UI won’t reflect progress : all items will appear in the ListBox at the same time after the collection is filled, instead of appearing as they are added to the collection. It can be annoying in some cases : for instance, if the ListBox is used to display search results, the user expects to see the results as they are found, like in Windows Search.

A simple way to achieve the desired behavior is to inherit ObservableCollection and override OnCollectionChanged and OnPropertyChanged so that the events are raised on the main thread (actually, the thread that created the collection). The AsyncOperation class is perfectly suited for this need : it allows to “post” a method call on the thread that created it. It is used, for instance, in the BackgroundWorker component, and in many asynchronous methods in the framework (PictureBox.LoadAsync, WebClient.DownloadAsync, etc…).

So, here’s the code of an AsyncObservableCollection class, that can be modified from any thread, and still notify the UI when it is modified :

    public class AsyncObservableCollection<T> : ObservableCollection<T>
    {
        private AsyncOperation asyncOp = null;

        public AsyncObservableCollection()
        {
            CreateAsyncOp();
        }

        public AsyncObservableCollection(IEnumerable<T> list)
            : base(list)
        {
            CreateAsyncOp();
        }

        private void CreateAsyncOp()
        {
            // Create the AsyncOperation to post events on the creator thread
            asyncOp = AsyncOperationManager.CreateOperation(null);
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            // Post the CollectionChanged event on the creator thread
            asyncOp.Post(RaiseCollectionChanged, e);
        }

        private void RaiseCollectionChanged(object param)
        {
            // We are in the creator thread, call the base implementation directly
           base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
        }

        protected override void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            // Post the PropertyChanged event on the creator thread
            asyncOp.Post(RaisePropertyChanged, e);
        }

        private void RaisePropertyChanged(object param)
        {
            // We are in the creator thread, call the base implementation directly
            base.OnPropertyChanged((PropertyChangedEventArgs)param);
        }
    }

The only constraint when using this class is that instances of the collection must be created on the UI thread, so that events are raised on that thread.

In the previous example, the only thing to change to make the collection modifiable across threads is the instantiation of the collection in the ViewModel :

private ObservableCollection<string> _strings = new AsyncObservableCollection<string>();

The ListBox can now reflect in real-time the changes made on the collection.

Enjoy ;)

Update : I just found a bug in my implementation : in some cases, using Post to raise the event when the collection is modified from the main thread can cause unpredictable behavior. In that case, the event should of course be raised directly on the main thread, after checking that the current SynchronizationContext is the one in which the collection was created. This also made me realize that the AsyncOperation actually doesn’t bring any benefit : we can use the SynchronizationContext directly instead. So here’s the new implementation :

    public class AsyncObservableCollection<T> : ObservableCollection<T>
    {
        private SynchronizationContext _synchronizationContext = SynchronizationContext.Current;

        public AsyncObservableCollection()
        {
        }

        public AsyncObservableCollection(IEnumerable<T> list)
            : base(list)
        {
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (SynchronizationContext.Current == _synchronizationContext)
            {
                // Execute the CollectionChanged event on the current thread
                RaiseCollectionChanged(e);
            }
            else
            {
                // Raises the CollectionChanged event on the creator thread
                _synchronizationContext.Send(RaiseCollectionChanged, e);
            }
        }

        private void RaiseCollectionChanged(object param)
        {
            // We are in the creator thread, call the base implementation directly
            base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
        }

        protected override void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (SynchronizationContext.Current == _synchronizationContext)
            {
                // Execute the PropertyChanged event on the current thread
                RaisePropertyChanged(e);
            }
            else
            {
                // Raises the PropertyChanged event on the creator thread
                _synchronizationContext.Send(RaisePropertyChanged, e);
            }
        }

        private void RaisePropertyChanged(object param)
        {
            // We are in the creator thread, call the base implementation directly
            base.OnPropertyChanged((PropertyChangedEventArgs)param);
        }
    }

Update: changed the code to use Send instead of Post. Using Post caused the event to be raised asynchronously on the UI thread, which could cause a race condition if the collection was modified again before the previous event was handled.

[WPF] Automatically sort a GridView when a column header is clicked

Very poorPoorAverageGoodExcellent (14 votes) 
Loading ... Loading ...

It’s quite simple, in WPF, to present data in a grid, thanks to the GridView class. If you want to sort it, however, it gets a little harder… With the DataGridView in Windows Forms, it was “automagic” : when the user clicked a column header, the grid was automatically sorted. To achieve the same behavior in WPF, you need to get your hands dirty… The method recommended by Microsoft is described in this article ; it is based on the Click event of the GridViewColumnHeader class. In my view, this approach has two major drawbacks :

  • The sorting must be done in code-behind, something we usually want to avoid if the application is designed according to the MVVM pattern. It also makes the code harder to reuse.
  • This method assumes that the text of the column header is also the name of the property to use as the sort criteria, which isn’t always true, far from it… We could use the DisplayMemberBinding of the column, but it’s not always set (for instance if a CellTemplate is defined instead).

After spending a long time trying to find a flexible and elegant approach, I came up with an interesting solution. It consists of a class with a few attached properties that can be set in XAML.

This class can be used as follows :

    <ListView ItemsSource="{Binding Persons}"
          IsSynchronizedWithCurrentItem="True"
          util:GridViewSort.AutoSort="True">
        <ListView.View>
            <GridView>
                <GridView.Columns>
                    <GridViewColumn Header="Name"
                                    DisplayMemberBinding="{Binding Name}"
                                    util:GridViewSort.PropertyName="Name"/>
                    <GridViewColumn Header="First name"
                                    DisplayMemberBinding="{Binding FirstName}"
                                    util:GridViewSort.PropertyName="FirstName"/>
                    <GridViewColumn Header="Date of birth"
                                    DisplayMemberBinding="{Binding DateOfBirth}"
                                    util:GridViewSort.PropertyName="DateOfBirth"/>
                </GridView.Columns>
            </GridView>
        </ListView.View>
    </ListView>

The GridViewSort.AutoSort property enables automatic sorting for the ListView. The GridViewSort.PropertyName property, defined for each column, indicates the property to use as the sort criteria. There is no extra code to write. A click on a column header triggers the sorting on this column ; if the ListView is already sorted on this column, the sort order is reversed.

In case you need to handle the sorting manually, I also added a GridViewSort.Command attached property. When used with the MVVM pattern, this property allows you to bind to a command declared in the ViewModel :

    <ListView ItemsSource="{Binding Persons}"
          IsSynchronizedWithCurrentItem="True"
          util:GridViewSort.Command="{Binding SortCommand}">
    ...

The sort command takes as parameter the name of the property to use as the sort criteria.

Note : if both the Command and AutoSort properties are set, Command has priority. AutoSort is ignored.

Here is the full code of the GridViewSort class :

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace Wpf.Util
{
    public class GridViewSort
    {
        #region Attached properties

        public static ICommand GetCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(CommandProperty);
        }

        public static void SetCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(CommandProperty, value);
        }

        // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached(
                "Command",
                typeof(ICommand),
                typeof(GridViewSort),
                new UIPropertyMetadata(
                    null,
                    (o, e) =>
                    {
                        ItemsControl listView = o as ItemsControl;
                        if (listView != null)
                        {
                            if (!GetAutoSort(listView)) // Don't change click handler if AutoSort enabled
                            {
                                if (e.OldValue != null && e.NewValue == null)
                                {
                                    listView.RemoveHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click));
                                }
                                if (e.OldValue == null && e.NewValue != null)
                                {
                                    listView.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click));
                                }
                            }
                        }
                    }
                )
            );

        public static bool GetAutoSort(DependencyObject obj)
        {
            return (bool)obj.GetValue(AutoSortProperty);
        }

        public static void SetAutoSort(DependencyObject obj, bool value)
        {
            obj.SetValue(AutoSortProperty, value);
        }

        // Using a DependencyProperty as the backing store for AutoSort.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AutoSortProperty =
            DependencyProperty.RegisterAttached(
                "AutoSort",
                typeof(bool),
                typeof(GridViewSort),
                new UIPropertyMetadata(
                    false,
                    (o, e) =>
                    {
                        ListView listView = o as ListView;
                        if (listView != null)
                        {
                            if (GetCommand(listView) == null) // Don't change click handler if a command is set
                            {
                                bool oldValue = (bool)e.OldValue;
                                bool newValue = (bool)e.NewValue;
                                if (oldValue && !newValue)
                                {
                                    listView.RemoveHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click));
                                }
                                if (!oldValue && newValue)
                                {
                                    listView.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click));
                                }
                            }
                        }
                    }
                )
            );

        public static string GetPropertyName(DependencyObject obj)
        {
            return (string)obj.GetValue(PropertyNameProperty);
        }

        public static void SetPropertyName(DependencyObject obj, string value)
        {
            obj.SetValue(PropertyNameProperty, value);
        }

        // Using a DependencyProperty as the backing store for PropertyName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PropertyNameProperty =
            DependencyProperty.RegisterAttached(
                "PropertyName",
                typeof(string),
                typeof(GridViewSort),
                new UIPropertyMetadata(null)
            );

        #endregion

        #region Column header click event handler

        private static void ColumnHeader_Click(object sender, RoutedEventArgs e)
        {
            GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
            if (headerClicked != null)
            {
                string propertyName = GetPropertyName(headerClicked.Column);
                if (!string.IsNullOrEmpty(propertyName))
                {
                    ListView listView = GetAncestor<ListView>(headerClicked);
                    if (listView != null)
                    {
                        ICommand command = GetCommand(listView);
                        if (command != null)
                        {
                            if (command.CanExecute(propertyName))
                            {
                                command.Execute(propertyName);
                            }
                        }
                        else if (GetAutoSort(listView))
                        {
                            ApplySort(listView.Items, propertyName);
                        }
                    }
                }
            }
        }

        #endregion

        #region Helper methods

        public static T GetAncestor<T>(DependencyObject reference) where T : DependencyObject
        {
            DependencyObject parent = VisualTreeHelper.GetParent(reference);
            while (!(parent is T))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
            if (parent != null)
                return (T)parent;
            else
                return null;
        }

        public static void ApplySort(ICollectionView view, string propertyName)
        {
            ListSortDirection direction = ListSortDirection.Ascending;
            if (view.SortDescriptions.Count > 0)
            {
                SortDescription currentSort = view.SortDescriptions[0];
                if (currentSort.PropertyName == propertyName)
                {
                    if (currentSort.Direction == ListSortDirection.Ascending)
                        direction = ListSortDirection.Descending;
                    else
                        direction = ListSortDirection.Ascending;
                }
                view.SortDescriptions.Clear();
            }
            if (!string.IsNullOrEmpty(propertyName))
            {
                view.SortDescriptions.Add(new SortDescription(propertyName, direction));
            }
        }

        #endregion
    }
}

Of course, this class could probably be improved… for instance, we could add an arrow glyph on the sorted column (maybe by using an Adorner). Maybe I’ll do that someday… meanwhile, please feel free to use it ;)

Update : A new version that displays the sort glyph in the sorted column is now available in this blog post.

[WPF] Using InputBindings with the MVVM pattern

Very poorPoorAverageGoodExcellent (6 votes) 
Loading ... Loading ...

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 :

    &lt;UserControl.InputBindings&gt;
        &lt;KeyBinding Modifiers=&quot;Control&quot; Key=&quot;E&quot; Command=&quot;{Binding EditCommand}&quot;/&gt;
    &lt;/UserControl.InputBindings&gt;

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 :

    &lt;UserControl.InputBindings&gt;
        &lt;KeyBinding Modifiers=&quot;Control&quot; Key=&quot;E&quot; Command=&quot;{input:CommandBinding EditCommand}&quot;/&gt;
    &lt;/UserControl.InputBindings&gt;

(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(&quot;commandName&quot;)]
        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 &quot;_context&quot; of type ParserContext
                ParserContext parserContext = GetPrivateFieldValue&lt;ParserContext&gt;(serviceProvider, &quot;_context&quot;);
                if (parserContext != null)
                {
                    // A ParserContext has a private field &quot;_rootElement&quot;, which returns the root element of the XAML file
                    FrameworkElement rootElement = GetPrivateFieldValue&lt;FrameworkElement&gt;(parserContext, &quot;_rootElement&quot;);
                    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 &amp;&amp; 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&lt;T&gt;(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] Article about the Model-View-ViewModel design pattern, by Josh Smith

Very poorPoorAverageGoodExcellent (No Ratings Yet) 
Loading ... Loading ...

Soon after the release of WPF, people have been talking more and more about “Model-View-ViewModel” (MVVM). This expression refers to a design pattern, drawing its inspiration from the Model-View-Controller (MVC) and Presentation Model (PM) patterns, and created specifically to take advantage of WPF features. This patterns enables an excellent decoupling between data, behavior and presentation, which makes the code easier to understand and maintain, and improves the collaboration between developers and designers. Another benefit of MVVM is the ability to write testable code much more easily.

If you want to know more about this pattern, I urge you to read the excellent article by Josh Smith on this topic, published in the February issue of the MSDN Magazine : WPF Apps With The Model-View-ViewModel Design Pattern.

Walking through a simple but concrete example, Josh Smith addresses most aspects of the MVVM pattern :

  • Data binding
  • Commands
  • Validation
  • Unit testing

Further more, the provided source code makes a good starting point to build a WPF application conforming to the MVVM pattern, and is also a mine of practical examples.

css.php