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
And the answer is, of course you can! After all, is there something you cannot do with the mighty WPF
Very simple isn’t it! Here is the MSDN description of the methods of this interface
Defines the method that determines whether the command can execute in its current state.
Defines the method to be called when the command is invoked.
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.
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
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
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…
and to create a command now is as simple as this…
and yes you could say that it is a 1 line of code (well a long one maybe )… yet of course, you can have as much logic in there as you want!
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?
That was easy wasn’t it! Now that you have the ICollectionView at hand, what can you do with it?
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
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.
You can also do sorting of data by using the ICollectionView. This can be done in a super easy way by using SortDescriptions.
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…
(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: http://marlongrech.wordpress.com/2008/04/20/part1-avaloncontrolslibrary-datagridview/ (See the Section, “Sorting the data in the DataGridView (and also ListView)” )
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…
(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…
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!
(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
The API also exposes an event that is fired when ever the current item changes so you can react when the current item changes
You can also change the selected item by using one of the following methods
- 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
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
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.
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
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.
Finally I got to meet another WPF Disciple, Corrado Cavalli the Italian WPF Disciple
Corrado is a great guy, I really enjoyed chatting with him. Here is a photo of us after a nice good geeky chat…
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