Sorting a WPF ListView in Grid Mode

There is an article on MSDN that demonstrates how to enable sorting column for a ListView used with Grid layout. The solution presented there works perfectly, but I do not want to put code behind my windows, because I work with MVVM approach. The solution is wrapping everything in a behavior, so I took the code from original MSDN example and I wrapped inside a behavior.

public class ListViewGridSortableBehavior : Behavior
    {
        protected override void OnAttached()
        {
            if (AssociatedObject != null)
            {
                AssociatedObject.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(GridHeaderClickEventHandler));
            }
            base.OnAttached();
        }

        GridViewColumnHeader _lastHeaderClicked = null;
        ListSortDirection _lastDirection = ListSortDirection.Ascending;

        void GridHeaderClickEventHandler(object sender, RoutedEventArgs e)
        {
            GridViewColumnHeader headerClicked =
                  e.OriginalSource as GridViewColumnHeader;
            ListSortDirection direction;

            if (headerClicked != null)
            {
                if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
                {
                    if (headerClicked != _lastHeaderClicked)
                    {
                        direction = ListSortDirection.Ascending;
                    }
                    else
                    {
                        if (_lastDirection == ListSortDirection.Ascending)
                        {
                            direction = ListSortDirection.Descending;
                        }
                        else
                        {
                            direction = ListSortDirection.Ascending;
                        }
                    }

                    if (_lastHeaderClicked != null) 
                    {
                        SetSortDownVisibility(_lastHeaderClicked, Visibility.Collapsed);
                        SetSortUpVisibility(_lastHeaderClicked, Visibility.Collapsed);
                    }

                    //string header = headerClicked.Column.Header as string;
                    String sortString = GetSortHeaderString(headerClicked);
                    if (String.IsNullOrEmpty(sortString)) return;

                    Sort(sortString, direction);

                    if (direction == ListSortDirection.Ascending)
                    {
                        SetSortDownVisibility(headerClicked, Visibility.Collapsed);
                        SetSortUpVisibility(headerClicked, Visibility.Visible);
                    }
                    else
                    {
                        SetSortDownVisibility(headerClicked, Visibility.Visible);
                        SetSortUpVisibility(headerClicked, Visibility.Collapsed);
                    }

                    // Remove arrow from previously sorted header 
                    if (_lastHeaderClicked != null && _lastHeaderClicked != headerClicked)
                    {
                        _lastHeaderClicked.Column.HeaderTemplate = null;
                    }


                    _lastHeaderClicked = headerClicked;
                    _lastDirection = direction;
                }
            }

        }
        private void Sort(string sortBy, ListSortDirection direction)
        {
            ICollectionView dataView =
              CollectionViewSource.GetDefaultView(AssociatedObject.ItemsSource);

            dataView.SortDescriptions.Clear();
            SortDescription sd = new SortDescription(sortBy, direction);
            dataView.SortDescriptions.Add(sd);
            dataView.Refresh();
        }

        public static readonly DependencyProperty SortHeaderStringProperty =
           DependencyProperty.RegisterAttached
           (
               "SortHeaderString",
               typeof(String),
               typeof(GridViewColumnHeader),
               new UIPropertyMetadata(String.Empty)
           );

        public static String GetSortHeaderString(DependencyObject obj)
        {
            return (String)obj.GetValue(SortHeaderStringProperty);
        }

        public static void SetSortHeaderString(DependencyObject obj, String value)
        {
            obj.SetValue(SortHeaderStringProperty, value);
        }

        public static readonly DependencyProperty SortDownVisibilityProperty =
          DependencyProperty.RegisterAttached
          (
              "SortDownVisibility",
              typeof(Visibility),
              typeof(GridViewColumnHeader),
              new UIPropertyMetadata(Visibility.Collapsed)
          );

        public static Visibility GetSortDownVisibility(DependencyObject obj)
        {
            return (Visibility)obj.GetValue(SortDownVisibilityProperty);
        }

        public static void SetSortDownVisibility(DependencyObject obj, Visibility value)
        {
            obj.SetValue(SortDownVisibilityProperty, value);
        }

        public static readonly DependencyProperty SortUpVisibilityProperty =
         DependencyProperty.RegisterAttached
         (
             "SortUpVisibility",
             typeof(Visibility),
             typeof(GridViewColumnHeader),
             new UIPropertyMetadata(Visibility.Collapsed)
         );

        public static Visibility GetSortUpVisibility(DependencyObject obj)
        {
            return (Visibility)obj.GetValue(SortUpVisibilityProperty);
        }

        public static void SetSortUpVisibility(DependencyObject obj, Visibility value)
        {
            obj.SetValue(SortUpVisibilityProperty, value);
        }
    }

The code is really simple, I just add and handler to the ClickEvent of the GridViewColumnHeader for the ListView and then used the code from MSDN example to do the sorting. I’ve added also a couple of Dependency Properties called SortDownVisibility and SortUpVisibility that determines the visibility of graphical indicator of the current sorting. I also added a property called SortHeaderString that will contains the name of the property that should be used to sort. Thanks to this simple code I can simply enable sorting in XAML.

<ListView ItemsSource="{Binding SearchesResult}" HorizontalContentAlignment="Stretch" >
    <i:Interaction.Behaviors>
        <Behaviours:ListViewGridSortableBehavior />
    </i:Interaction.Behaviors>

Now I need to enable sorting for all sortable columns, using my SortHeaderString property.

<GridViewColumn  DisplayMemberBinding="{Binding Dto.Author}" >
    <GridViewColumn.Header>
        <GridViewColumnHeader Behaviours:ListViewGridSortableBehavior.SortHeaderString="Dto.Author">
            <StackPanel Orientation="Horizontal">
                <Label Content="?" Visibility="{Binding Path=SortDownVisibility, RelativeSource={RelativeSource AncestorType={x:Type GridViewColumnHeader}}}"></Label>
                <Label Content="?" Visibility="{Binding Path=SortUpVisibility, RelativeSource={RelativeSource AncestorType={x:Type GridViewColumnHeader}}}"></Label>
                <Label Content="Author"></Label>
            </StackPanel>
        </GridViewColumnHeader>
    </GridViewColumn.Header>
</GridViewColumn>

Thanks to my Dependency Properties, it is really simple to enable sorting for a column because I need only to populate the SortHeaderString property of the Header. In previous example, the column is bound to Dto.Author property, the header shows the string Author, and I’ve also added a couple of Arrows to show the actual sorting. No resource is needed because I’ve used a couple of Unicode chars to represent up and down arrows.

Here is the result

image

Figure 1: Clickable and sortable header in ListView with Grid layout

This simple approach is perfectly compatible with MVVM and permits you to choose the exact layout of the header while maintaining the option to sort with clickable headers.

Gian Maria.

ConventionalCommand in MVVM architecture

The original idea of ConventionalCommand was taken by Radical Framework of my dear friend Mauro, the purpose is using a Convention over Configuration to bind Ui element to Commands in a MVVM architecture. You can find a real good and complete implementation of this concept in Radical, but I created a custom smaller and trivial stand-alone implementation to use in some of my project based on custom MVVM architecture. If you need a more robust and mature implementation I suggest you to have a look at Radical, but if you already have some custom code and you do not want to introduce dependency to an entire library only to use this concept I will show you how simple is to create a Command object that is capable to binding to MVVM methods based on Conventions.

My typical ViewModel usually exposes one property of type DelegateCommand for each Command it implements and needs to initialize all commands with a  Fluent-like interface.

     public DelegateCommand InsertLink { get; private set; }
.....
     public void InitializeCommands() {
            InsertLink = AsyncDelegateCommand.Create(this)
                .OnCanExecute(o => !String.IsNullOrEmpty(UrlToNavigate))
                .WaitMessage("Saving")
                .MonitorProperty(vm => vm.UrlToNavigate)
                .OnExecuteAsync(ExecuteInsert);

As you can see initialization code define the CanExecute lambda, used by WPF to ask if the command can be executed, the WaitMessage specify the message to show in the UI during command execution (UI is disabled during command execution). MonitorProperty permits to specify properties that are used by the CanExecute lambda, whenever one of these property changes (you can call multiple time the MonitorProperty, once for each property you want to watch) AsyncDelegateCommand tells WPF to reevaluate the CanExecute lambda, finally the OnExecuteAsync specify the method to call when the command is invoked.

This structure has the advantage to create Designer-Bindable commands, if you drop a button in the UI in blend, you can then browse all properties of ViewModel and choose the command to bind to the Button.Command property, but you have to type a lot of plumbing code in ViewModel for each command you want to implement and this started to become annoying. If you do not care to see available commands in blend designer, you can create a ConventionalCommand that operates based on convention. Here is the full code.

    public class ConventionalCommand : ICommand
    {
        private FrameworkElement boundObject;

        private String commandName;

        private Boolean isAsync;

        private String waitMessage;

        public ConventionalCommand(FrameworkElement boundObject, String commandName, Boolean isAsync, String waitMessage)
        {
            this.boundObject = boundObject;
            this.commandName = commandName;
            this.isAsync = isAsync;
            this.waitMessage = waitMessage;
            RelatedViewModel = boundObject.DataContext as BaseViewModel;
            this.boundObject.DataContextChanged += boundObject_DataContextChanged;
        }

        void boundObject_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            RelatedViewModel = e.NewValue as BaseViewModel;
        }

        BaseViewModel relatedViewModel;
        MethodInfo canExecute;
        MethodInfo execute;

        private BaseViewModel RelatedViewModel
        {

            get
            {
                return relatedViewModel;
            }
            set
            {
                if (relatedViewModel != null) {
                    relatedViewModel.PropertyChanged -= relatedViewModel_PropertyChanged;
                }
                relatedViewModel = value;
                if (relatedViewModel != null)
                {
                    Type vmt = relatedViewModel.GetType();
                    canExecute = vmt.GetMethod("CanExecute" + commandName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
                    execute = vmt.GetMethod("Execute" + commandName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
                    if (execute == null) {
                        Debug.WriteLine("Binding Error - Command Execute" + commandName + " not found in viewmodel of type " + vmt.GetType());
                    }
                    relatedViewModel.PropertyChanged += relatedViewModel_PropertyChanged;
                }
                OnCanExecuteChanged();
            }
        }

        void relatedViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "CanExecute" + commandName) 
            {
                OnCanExecuteChanged();
            }
        }

        public event EventHandler CanExecuteChanged;

        protected virtual void OnCanExecuteChanged()
        {
            EventHandler temp = CanExecuteChanged;
            if (temp != null)
            {
                temp(this, EventArgs.Empty);
            }
        }

        public bool CanExecute(object parameter)
        {
            if (RelatedViewModel == null) return false;
            if (canExecute == null) return true;

            return (Boolean)canExecute.Call(RelatedViewModel, new Object[] { parameter });
        }

        public void Execute(object parameter)
        {
            if (RelatedViewModel == null) return;

            if (!isAsync)
            {
                execute.Call(RelatedViewModel, new Object[] { parameter });
            }
            else 
            {
                RelatedViewModel.Execute(() => execute.Call(RelatedViewModel, new Object[] { parameter }), true, waitMessage);
            }
            
        }
    }

ConventionalCommand is based on the following assumption. It has a commandName field used to specify the name of the command and given this name the following conventions are used

  1. Method name on the ViewModel that executes the command should be called ExecuteXXX where XXX is commandName value.
  2. The function that determines if the command can be executed should be called CanExecuteXXX where XXX is commandName value
  3. The reevaulation of the CanExecuteXXX is done if the viewmodel raise a property changed with property name CanExecuteXXX (even if a property with such a name does not exists).

To avoid suffering performance penalties due to invocation through reflection I’ve simply used the FastReflect library that uses LCG to invoke methods at runtime. The code is really trivial, is based on a custom MVVM architecture it stores the ViewModel that contains the method that implement the command inside a RelatedViewModel property and then it uses RelatedViewModelExecute method to execute some code asynchronously and automatically setting the ViewModel in Busy status until the command finishes.

The main problem you need to face with such a structure is due to the fact that you have no control over binding execution ordering and this is a problem to find the reference to RelatedViewModel. If you look at the code you can see that constructor accepts a reference to the FrameworkElement that is used for the binding (Es. a Button) and the command register itself to the DataContextChanged event. This is needed because you need to determine the value of RelatedViewModel at runtime from the DataContext property of FrameworkEement that is binding to the ConventionalCommand. Thanks to DataContextChanged I can simply monitor whenever the DataContext of the FrameworkElement changed and update RelatedViewModel accordingly. This makes me indipendent from the order of binding execution, if the ConventionalCommand is created before DataContext of framework element is set, I do not have problem because I’ll be notified of the DataContext property changed when binding engine will change DataContext of Frameworkelement. All reflection code is inside the setter of RelatedViewModel and is really trivial code that does not work explanation.

To easy the use of this command you need a MarkupExtension and I decided to call it MvvmCommand,

    public class MvvmCommand : MarkupExtension
    {

        /// <summary>
        /// This is the path of the command, the ViewModel should have a method called ExecutePath to 
        /// make everything work.
        /// </summary>
        public String CommandName { get; set; }

        [DefaultValue(false)]
        public Boolean IsAsync { get; set; }

        [DefaultValue("")]
        public String WaitMessage { get; set; }

        public MvvmCommand()
        {
            WaitMessage = String.Empty;
            CommandName = String.Empty;
        }

        public MvvmCommand(String path) : this() 
        {
            this.CommandName = path;
        }

        /// <summary>
        /// we need to provide the ICommand that will take care of command invocation.
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <returns></returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var service = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
            if (service == null) return false;

            FrameworkElement dobj = service.TargetObject as FrameworkElement;
            if (dobj == null) throw new ApplicationException("Cannot do Conventional Command Binding");
            return new ConventionalCommand(dobj, CommandName, IsAsync, WaitMessage);
        }
    }

Thanks to this structure when I need to bind Command property of a control in the Ui to a method of the ViewModel I can simply write:

<Button Content="SaveAll"  Command="{mvvm:MvvmCommand SaveCustomer}"/>

This declaration binds the button command to a SaveCustomer command so it looks for CanExecuteSaveCustomer and ExecuteSaveCustomer methods inside ViewModel. You do not need to create DelegateCommand property in ViewModel nor you need to create the command, you should only declare the above two methods and be sure that whenever you want WPF binding engine to reevaluate CanExecuteSaveCustomer you should raise a PropertyChanged event of the “CanExecuteSaveCustomer” fictional property.  To easy this last part I can write this code thanks to the PropertyLink helper

            PropertyLink.OnObject(this)
                .Link(vm => vm.UserEmail, "CanExecuteSaveCustomer")
                .Link(vm => vm.UserName, "CanExecuteSaveCustomer")

This code is contained in the constructor of ViewModel and basically is used to link notification of properties together. The above code means, link property on this ViewModel and whenever the UserEmail changes notify also the change ov CanExecuteSaveCustomer. The only ugly part is that you need to specify the name of linked property with a string, because there is no real property CanExecuteSaveCustomer on the ViewModel.

Gian Maria.

How simple is creating UI in WPF

I have this UI already working, it is a simple interface where users are presented with a list of Customers object, for each customers some feature could be enabled or not, so we have nice checkboxes to immediately enable/disable a feature with One Click.

image

Figure 1: Actual situation all the checkboxes are always enabled

But the very same form is used to edit customer details, so you need to select a row in the DataGrid and then started editing detailed information. Now the user want a little modification that permits to check various checkboxes only if the Customer row is selected, like shown in the following image

image

Figure 2: Desired result, only the checkboxes of selected row are enabled.

The image is small, but if you look closely only the checkboxes of the currently selected row are enabled and doing this in WPF is surprisingly simple.

 <DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
         <CheckBox 
                IsEnabled="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                AncestorType={x:Type DataGridRow}}, 
                Path=IsSelected}"

The solution is really really simple, since I’m using a DataGridTemplateColumn I have full control on the XAML used inside the column, and I can easily bind the IsEnabled property of controls to the IsSelected property of the first ancestor of type DataGridRow, that in turn is the row where the control resides.

Few lines of code, no C# code, MVVM and WPF is just beautiful.

Gian Maria.

Quick reminder on How-To map items of a list view to a VM command

The problem is really simple, but sometimes I see people tend to forget a little bit how the DataContext works in WPF and being stuck in wandering why a command is not invoked when a button inside a DataTemplate is pressed.

Suppose you have a ListView bounds to a list of items called SingleResult, for each SingleResult I have a complex layout and the main ViewModel contains a command that expect a SingleResult parameter called “ShowDetails” that simply shows the details of a SingleResult item. I see people do binding in this way.

image

Figure 1: Code to bind a button to a command

When the program runs this is the UI.

image

Figure 2: The UI in action.

Now clicking on the Details button makes nothing to happen. The reason is quite simple, with the syntax in Figure 1, you are actually binding the command to the ShowDetails command of the SingleResult item bound to that row.

This happens because the code is inside a DataTemplate, and the DataContext is the specific object used to render the row. In an good MVVM scenario the SingleResult object should have ShowDetails command and everything works good, but if you prefer to define the command to the main ViewModel, you need to change the syntax in this way.

   1: Command="{Binding DataContext.ShowDetails, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" 

This code works because the command is bound to the ShowDetails defined on the DataContext of the ancestor of type Window, thus, actually binding to the main ViewModel.

Alk.

Tags:

Event to Command in WPF MVVM application

I needed a simple way to obtain this simple result: whenever a certain component in the UI (a WebBrowser control) raises some specific event, I want a command in the VM to be executed, without the need to specify any command parameter. The only requirement I want is avoiding a single line of code in the UI :) because, having no code in the UI is one of the main benefit of the MVVM model.

image

To keep everything simple I want a simple syntax that permits me to specify that when an event of type X is raised, a command of name Y should be called.

   1: <Controls:xxxWebBrowserManagerFlexible x:Name="wbBrowser" Margin="0,0,0,0"

   2:                BrowserType="InternetExplorer"   

   3:                Links="{Binding LinksOfThePage}"

   4:                Behaviours:EventToCommandBehavior.Bind="DocumentCompleted-SignalDocumentComplete"

   5:                RawHtmlContent="{Binding FullHtmlContent, Mode=TwoWay}"

   6:                SelectedText="{Binding BrowserSelectedText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

   7:                CurrentUrl="{Binding UrlToNavigate, Mode=TwoWay}" />

As you can see I created a simple behavior called EventToCommandBehavior that accepts a very simple syntax: a string of format EvenName-CommandName. This solution probably is not so elegant, it has no intellisense or designer support, but it works and it is supersimple. My Behavior has an Attached property called Bind

   1: public static readonly DependencyProperty BindProperty =

   2:    DependencyProperty.RegisterAttached

   3:    (

   4:        "Bind",

   5:        typeof(String),

   6:        typeof(EventToCommandBehavior),

   7:        new UIPropertyMetadata(String.Empty, OnBindChanged)

   8:    );

All the dirty work is done inside the OnBindChanged.

   1: private static Dictionary<Object, String> _routes

   2:      = new Dictionary<object, String>();

   3:  

   4:  private static void OnBindChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args)

   5:  {

   6:      if (String.IsNullOrWhiteSpace((String) args.NewValue)) return;

   7:  

   8:      String[] bind = ((String) args.NewValue).Split('-');

   9:  

  10:      EventInfo ev = dpo.GetType().GetEvent(bind[0]);

  11:      MethodInfo handler = typeof(EventToCommandBehavior)

  12:          .GetMethod("Handler", BindingFlags.NonPublic | BindingFlags.Static);

  13:      var eh = Delegate.CreateDelegate(ev.EventHandlerType, null, handler);

  14:      var minfo = ev.GetAddMethod();

  15:      minfo.Invoke(dpo, new object[] { eh });

  16:      

  17:      //now go for the command.

  18:      _routes.Add(dpo, bind[1]);

  19:  }

The core part is finding the EventInfo for choosen event, and create dynamically an handler capable to handle every event. The association between EventName and CommandName is stored inside a dictionary object, and the handler is really simple, just get a reference to the command with reflection and call the Execute method.

   1: private static void Handler(Object sender, EventArgs e)

   2:  {

   3:      String commandName;

   4:      if (_routes.TryGetValue(sender, out commandName))

   5:      {

   6:          FrameworkElement fe = sender as FrameworkElement;

   7:          if (fe.DataContext != null)

   8:          {

   9:              PropertyInfo pinfo = fe.DataContext.GetType().GetProperty(commandName);

  10:              if (pinfo != null)

  11:              {

  12:                  ICommand command = (ICommand) pinfo.GetValue(fe.DataContext, null);

  13:                  if (command.CanExecute(null))

  14:                  {

  15:                      command.Execute(null);

  16:                  }

  17:              }

  18:          }

  19:      }

  20:  }

Since the View Model that contains the ICommand is the DataContext of the element that raised the event, I simply use the GetProperty() method to find the right ICommand, and finally call the Execute method to actually call the command. Since one of the prerequisites states that we need to pass no command parameters, I simply pass null to Execute method.

Alk.