Avoiding CommandBinding in the XAML Code Behind files

Yesterday I got a very good question from a colleague. Basically we were discussing the M-V-VM pattern and how it makes your XAML code behind much cleaner + your application more testable. The only thing that was annoying him was the fact that he had to do the command binding and delegate the work to the ViewModel . So he asked me, “Is there a way how I can remove the Command Binding from my code behind as well?”. What he was referring to, was the hooking of Commands to the ViewModel, which would look something like this

   1: CommandBindings.Add(
   2:     new CommandBinding(Commands.Search,
   3:     (x, e) => vm.Search(),
   4:     (x, e) => e.CanExecute = vm.CanSearch())
   5:     );

And the answer is, of course you can! After all, is there something you cannot do with the mighty WPF :P

So how can we achieve this? We have to create a class that implements the ICommand interface. Here is how the ICommand interface looks like.

   1: public interface ICommand
   2: {
   3:     event EventHandler CanExecuteChanged;
   4:  
   5:     bool CanExecute(object parameter);
   6:  
   7:     void Execute(object parameter);
   8: }

Very simple isn’t it! Here is the MSDN description of the methods of this interface

ms616874.pubmethod(en-us,VS.90).gif
CanExecute
Defines the method that determines whether the command can execute in its current state.

ms616874.pubmethod(en-us,VS.90).gif
Execute
Defines the method to be called when the command is invoked.

ms616874.pubevent(en-us,VS.90).gif
CanExecuteChanged
Occurs when changes occur that affect whether or not the command should execute.

So in the CanExecute we have to put the logic that checks if we can execute the command and in the Execute we put the logic that executes the command…. but what about the CanExecuteChanged event? Well here we have to hook up to the Command System. Here is a simple implementation of the ICommand.

   1: public class SearchCommand : ICommand
   2: {
   3:     ViewModel viewModel;
   4:     public SearchCommand(ViewModel viewModel)
   5:     {
   6:         this.viewModel = viewModel;
   7:     }
   8:  
   9:     #region ICommand Members
  10:  
  11:     public bool CanExecute(object parameter)
  12:     {
  13:         return !String.IsNullOrEmpty(viewModel.SearchText);
  14:     }
  15:  
  16:     public event EventHandler CanExecuteChanged
  17:     {
  18:         add { CommandManager.RequerySuggested += value; }
  19:         remove { CommandManager.RequerySuggested -= value; }
  20:     }
  21:  
  22:     public void Execute(object parameter)
  23:     {
  24:         viewModel.MyDataView.Filter = x => ((Person)x).Name.Contains(viewModel.SearchText);
  25:     }
  26:  
  27:     #endregion
  28: }

  As you can see in order to hook up to the WPF command system we have to override the default behavior of the event and register to the CommandManager.RequerySuggested like so

   1: public event EventHandler CanExecuteChanged
   2: {
   3:     add { CommandManager.RequerySuggested += value; }
   4:     remove { CommandManager.RequerySuggested -= value; }
   5: }

This is very important because by doing so the CanExecute method will be called when ever there is focus changed, user input etc…

Once you have a class that implements the ICommand you can expose that class in your ViewModel and databind to it in the Command property of the control you want to hook up the command to like so

   1: ViewModel property
   2: /// <summary>
   3: /// Return an ICommand that can execute the search
   4: /// </summary>
   5: public ICommand SearchByNameCommand
   6: {
   7:     get { return searchByNameCommand; }
   8: }
   9:  
  10: XAML to hook to that command
  11: <Button Command="{Binding SearchByNameCommand}" Content="Search" />

And that’s it… No more command bindings to hook to the Command in the code behind of the XAML file! This is very cool but now I guess the next question would be, so we actually have to create a class and implement an ICommand every time??

Well the answer is HELL NO…. What I do is create a class that does all the stuff for me and then I pass a delegate for the CanExecute and another one for the Execute… as simple as this…

   1: public class SimpleCommand : ICommand
   2: {
   3:     public Predicate<object> CanExecuteDelegate { get; set; }
   4:     public Action<object> ExecuteDelegate { get; set; }
   5:  
   6:     #region ICommand Members
   7:  
   8:     public bool CanExecute(object parameter)
   9:     {
  10:         if (CanExecuteDelegate != null)
  11:             return CanExecuteDelegate(parameter);
  12:         return true;// if there is no can execute default to true
  13:     }
  14:  
  15:     public event EventHandler CanExecuteChanged
  16:     {
  17:         add { CommandManager.RequerySuggested += value; }
  18:         remove { CommandManager.RequerySuggested -= value; }
  19:     }
  20:  
  21:     public void Execute(object parameter)
  22:     {
  23:         if (ExecuteDelegate != null)
  24:             ExecuteDelegate(parameter);
  25:     }
  26:  
  27:     #endregion
  28: }

and to create a command now is as simple as this…

   1: searchByNameCommand = new SimpleCommand
   2: {
   3:     CanExecuteDelegate = x => !String.IsNullOrEmpty(SearchText),
   4:     ExecuteDelegate = x => myDataView.Filter = stateObj => ((Person)stateObj).Name.Contains(SearchText)
   5: };

and yes you could say that it is a 1 line of code :P (well a long one maybe :) )… yet of course, you can have as much logic in there as you want!

 

If you want to see a sample project I created a demo app that you can download here.

kick it on DotNetKicks.com

ICollectionView explained

Lately I have been getting a lot of questions on ICollectionView so I decided to write a very small post on how it works and some tips and tricks you might find useful when using it. ICollectionViews are used for filtering, sorting, grouping and also selecting items in list controls (selecting applies only for controls that inherit from the Selector base class such as ListBox, ComboBox etc..).

This is the MSDN documentation description of a ICollectionView :

“You can think of a collection view as a layer on top of a binding source collection that allows you to navigate and display the collection based on sort, filter, and group queries, all without having to manipulate the underlying source collection itself”

And yes I agree, it is a very powerful mechanism and helps a lot when you are separating “concerns” by using patterns such as M-V-VM.

So let’s start from the basics, how can I get an ICollectionView out of my collection?

   1: List<string> myData = new List<string>();
   2: ICollectionView view = CollectionViewSource.GetDefaultView(myData);

That was easy wasn’t it! Now that you have the ICollectionView at hand, what can you do with it?

Filtering

Let’s start by doing some filtering. Basically you can set a predicate to the Filter¬† property and this will cause the list to be filtered by that predicate. Something like this

   1: myDataView.Filter = delegate(object item)
   2: {
   3:     return item.Contains(SearchText);
   4: };

As you can see it is very easy to implement. This will take care of filtering items as they are added (if the collection implements the INotifyCollectionChanged).
(TIP) You can also do Filtering on more than one predicate. Have a look at how Beatriz Costa does this.

Sorting

You can also do sorting of data by using the ICollectionView. This can be done in a super easy way by using SortDescriptions.

   1: myDataView.SortDescriptions.Add(new SortDescription("ID", direction));

Where ‘ID’ is the name of the property which you want to sort on. (TIP) If you are going to apply more than one SortDescription at once use the DeferRefresh method so that you only apply a sort once. DeferRefresh will return an IDisposable object and once you call dispose the Refresh happens. So you can use it like so…

   1: using (myDataView.DeferRefresh()) // we use the DeferRefresh so that we refresh only once
   2: {
   3:     myDataView.SortDescriptions.Clear();
   4:     if (SortById)
   5:         myDataView.SortDescriptions.Add(new SortDescription("ID", direction));
   6:     if (SortByName)
   7:         myDataView.SortDescriptions.Add(new SortDescription("Name", direction));
   8: }

(TIP) This seems like a very nice way how to implement sorting but there is a very big performance penalty here. The SortDescriptions  are slow as an old granny (it uses reflection). If you are dealing with large data sets you should NOT be using this technique for sorting. Yet do not despair because there is an alternative; You can also do sorting by using CustomSort property on the ListCollectionView (this is the type of CollectionView that gets created when using a collection that implements an IList). Have a look here http://ligao101.wordpress.com/2007/07/31/a-much-faster-sorting-for-listview-in-wpf/.
(TIP) If you need to do sorting of ListViews so that when the user clicks on the ListView Column header it sorts, then you might want to have a look at this: https://marlongrech.wordpress.com/2008/04/20/part1-avaloncontrolslibrary-datagridview/ (See the Section, “Sorting the data in the DataGridView (and also ListView)” )

Grouping

This is yet another cool feature of the ICollectionView. Basically you can group data together by using the GroupDescriptions property of the ICollectionView. You can add a PropertyGroupDescription to the GroupDescriptions property and you are all set. Besides this you can also modify how the group looks by using a GroupStyle (which is applicable for all class that derive from ItemsControl). Here is some code for you to chew…

   1: C# code
   2: myDataView.GroupDescriptions.Add(new PropertyGroupDescription("Location"));
   3:
   4: XAML
   5: <ListView.GroupStyle>
   6:     <GroupStyle>
   7:         <GroupStyle.HeaderTemplate>
   8:             <DataTemplate>
   9:                 <TextBlock Text="{Binding Name}"/>
  10:             </DataTemplate>
  11:         </GroupStyle.HeaderTemplate>
  12:     </GroupStyle>
  13: </ListView.GroupStyle>

(TIP) If you want some custom grouping you should have a look at: http://www.beacosta.com/blog/?p=19. Basically you can use an IValueConverter to do your custom logic; let’s say you have an Age property and you want to do a group of under 16 and over 16. You can do that logic in the converter :)

(TIP) Grouping will disable the Virtualization support by default. So grouping for large data sets could be really expensive, think it twice before doing it…

Selection

One of my favorite features of the CollectionView is the support for Selection tracking, this really helps a lot when you are in the ViewModel and need to know what is happening in the UI (Typical example for this is, a Master-Detail screen). Basically if the ItemsControl( this is the base class for all controls that show lists or better that have the famous ItemsSource property ) you are using inherits from the Selector control (such as Listbox, Listview, ComboBox etc…) you can switch on the feature to keep track of the Selections. You do this by setting the IsSynchronizedWithCurrentItem property to True. This is very important! if you do not set this property the CollectionView selection features are not gonna work!

   1: <ListView ItemsSource="{Binding MyData}" IsSynchronizedWithCurrentItem="True">

(TIP) Before going to the details of what you can do with this let me point out one really cool thing. If you set the IsSynchronizedWithCurrentItem property to true on 2 ListBoxes(or any other control that derives from Selector) the 2 controls will keep the selection in sync :)

Now let’s have a look at what you can do with this. Lets start by seeing how we can check what is the currently selected item. Thanks to the pretty API the ICollectionView exposes all you have to do is call the property CurrentItem of the ICollectionView

   1: myDataView.CurrentItem

The API also exposes an event that is fired when ever the current item changes so you can react when the current item changes

   1: //when the current selected changes store it in the CurrentSelectedPerson
   2: myDataView.CurrentChanged += delegate
   3: {
   4:     //stores the current selected person
   5:     CurrentSelectedPerson = (Person)myDataView.CurrentItem;
   6: };

You can also change the selected item by using one of the following methods

- MoveCurrentToFirst
- MoveCurrentToLast
- MoveCurrentToNext
- MoveCurrentToPrevious
- MoveCurrentTo(x) (where x is the index you want to navigate to)

You can do some neat things with this. In the Demo app that I provide for download in this post you can see how I leverage RoutedCommands with the CanExecute mechanism to enable and disable the options for the selection navigation.

(TIP) If you are doing a method to check if the user can select the last item/next item and you are using filtering on the list always count the items in the CollectionView and not in the original list, like the following

   1: public bool CanSelectLastItem()
   2: {
   3:     //Please note that this is done in such a way and not in myData.Count because if there is filtering being applied we need to make sure that the count of items is correct!
   4:     return myDataView.CurrentPosition < myDataView.Cast<Person>().Count() - 1;
   5: }

Conclusion

ICollectionView is really a great tool especially when you are trying to separate the UI code from the business logic by using patterns such as M-V-VM. In the Demo application I compiled for this post you can see how to implement a nice ViewModel and use the ICollectionView to do all sort of stuff for the UI without having any problems because you do not have a reference to the UI objects. Having said all this sometimes complex scenarios make us move away from the ICollectionView… Still I believe that ICollectionViews finds a place in nearly all projects because they make your life much easier :)

Download Demo Application

kick it on DotNetKicks.com

Fix scrollbars for a dynamic layout in a Listview/ListBox

Some colleagues at work had a problem today with a ListView that had a dynamic layout. Basically we had a ListView that contained an Expander as one of the CellTemplates, the Expander had another ListBox inside that contained several items. The problem with this was that the ScrollBar for the ListView (which contained all the Expanders) was freaking out and behaving like it was drunk. Here is the XAML for this.

   1: <ListView ItemsSource="{Binding}" >
   2:     <ListView.View>
   3:         <GridView>
   4:             <GridViewColumn Header="Test">
   5:                 <GridViewColumn.CellTemplate>
   6:                     <DataTemplate>
   7:                         <Expander Header="Test">
   8:                             <ListBox ItemsSource="{Binding}">
   9:                                 <ListBox.ItemTemplate>
  10:                                     <DataTemplate>
  11:                                         <TextBlock Text="{Binding}"/>
  12:                                     </DataTemplate>
  13:                                 </ListBox.ItemTemplate>
  14:                             </ListBox>
  15:                         </Expander>
  16:                     </DataTemplate>
  17:                 </GridViewColumn.CellTemplate>
  18:             </GridViewColumn>
  19:         </GridView>
  20:     </ListView.View>
  21: </ListView>
  22:
  23: public Window1()
  24: {
  25:     DataContext = new[]
  26:         {
  27:             new [] { 50, 30, 20, 10, 40, 50, 70, 84, 20, 30, 50 },
  28:             new [] { 50, 30, 20, 10, 40, 50, 70, 84, 20, 30, 50 },
  29:             new [] { 50, 30, 20, 10, 40, 50, 70, 84, 20, 30, 50 },
  30:         };
  31:     InitializeComponent();
  32: }

In order to fix this there is a magic trick :)

All you have to do set an attached¬† property on the ListView to instruct it’s ScrollViewer that the Content cannot Scroll. so basically the XAML now would look like this

   1: <ListView ItemsSource="{Binding}" ScrollViewer.CanContentScroll="False">
   2:     <ListView.View>
   3:         <GridView>
   4:             <GridViewColumn Header="Test">
   5:                 <GridViewColumn.CellTemplate>
   6:                     <DataTemplate>
   7:                         <Expander Header="Test">
   8:                             <ListBox ItemsSource="{Binding}">
   9:                                 <ListBox.ItemTemplate>
  10:                                     <DataTemplate>
  11:                                         <TextBlock Text="{Binding}"/>
  12:                                     </DataTemplate>
  13:                                 </ListBox.ItemTemplate>
  14:                             </ListBox>
  15:                         </Expander>
  16:                     </DataTemplate>
  17:                 </GridViewColumn.CellTemplate>
  18:             </GridViewColumn>
  19:         </GridView>
  20:     </ListView.View>
  21: </ListView>

As you can see all I changed here is adding the attached property ScrollViewer.CanContentScroll=”False” on the ListView, and viola the scrolling now works correctly :)

Edit: After having a chat with a fellow WPF Disciple, Andrew Smith, he pointed out that this solution will drop Virtualization support. So if you have a lot of data this is probably not the best solution for you.

I’m at Tech Ed Barcelona

Hello everyone, you might be wondering what happened to me and why I am not blogging so much lately. Well I have been going through some tough times, yet hopefully from next week I will be back on my feet and start blogging like an animal again. Right now I am at Tech Ed Barcelona, here there should be some really cool stuff. I’m sure I will like something and trigger my next post :)

Anyone that is here at Tech Ed and want to meet up for coffee and some geek chat, send me an email or comment or something :)

lol… here is my happy with the Tech Ed gifts :P

 

DSCF3768