How insert Separator in a databound ComboBox
WPF December 8th, 2008As you might already know, I’m a big fan of the Model-View-ViewModel pattern. I’m using it extensively on the current I’m working on at work. Today I had to face a simple problem that was tricky to solve.
In the application I’m building, I have a “Library panel”. This panel contains a set of items that are used in my application. Because the number of items can be very large, I decided to add a filter capability. Filtering to a collection is very straightforward once you get familiar with the ICollectionView interface. If you want more details about it, check out Marlon’s blog post about it.
To give the user the possibility to filter the items, I added a ComboBox control. Of course, because I’m using the MVVM pattern, I’m not creating the ComboBoxItem myself, the databinding mechanism of WPF handle this (to be precise, the databinding handles collecting the item, and the ComboBox handles the creation of the ComboBoxItem to wrap them…).
The problem
In my ViewModel, I create a ObservableCollection<string> property that I called “Categories”.Then, in my view (XAML), I databound the ComboBox’s ItemsSource property to this “Categories”. Ok, it works fine and took me about 10min to do it.
Now, I want to add separator between some ComboBoxItem… Hmmm, how should I do that… I cannot do combobox.Items.Add(something) anymore because the ItemsSource property is databound… Well, I could as something in my ViewModel, but what ?
My solution
I wanted to keep the logical information about where Separator are in the ViewModel. This is typically an example of something that should stays in the ViewModel. I decided to add an empty items in my ObservableCollection for every Separator I wanter to have in the view.
In the view, I set up an ItemContainerStyle for my ComboBoxItem. The tricky part is, how could I replace my ComboBoxItem with a Separator… Well actually, we can’t. But what we can do is to change the entire template of the ComboBoxItem when the content is empty:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <ComboBox ItemsSource="{Binding Categories}"> <ComboBox.ItemContainerStyle> <Style TargetType="{x:Type ComboBoxItem}" BasedOn="{StaticResource {x:Type ComboBoxItem}}"> <Style.Triggers> <DataTrigger Binding="{Binding}" Value=""> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ComboBoxItem}"> <Separator HorizontalAlignment="Stretch" IsEnabled="False"/> </ControlTemplate> </Setter.Value> </Setter> </DataTrigger> </Style.Triggers> </Style> </ComboBox.ItemContainerStyle> </ComboBox> |
And voila ! It works fine and keeps the logic in the ViewModel. If you have any other idea about how we can solve this issue, please feel free to comment




December 8th, 2008 at 3:31 pm
Waouh… Tricky
December 19th, 2008 at 5:04 pm
Bien vu !
On pouvait aussi faire ça avec la propriété ItemTemplateSelector… mais c’est vrai que c’est classe de tout faire en XAML
October 2nd, 2009 at 11:30 am
If you don’t mind using the more general-purpose ObservableCollection instead of ObservableCollection, then you could simply add a Separator object in the binding source:
DataContext = new ObservableCollection
{
“Catergory 1″,
new Separator(),
“Catergory 2″,
“Catergory 3″,
};
October 2nd, 2009 at 11:35 am
Thomas, you’re right.
But IMHO I prefer not to have any UI-related stuff in my ViewModel classes
October 2nd, 2009 at 11:38 am
Erratum:
In post #3, should read
“…general-purpose ObservableCollection<object> instead of ObservableCollection<string>…”
February 28th, 2010 at 5:30 pm
Great, works fine!
June 8th, 2010 at 1:00 pm
I’ve also added a setter to DataTrigger, to make separators unselectable:
June 8th, 2010 at 2:53 pm
The previous suggestion doesn’t work.
The solution http://blog.alner.net/archive/2010/04/25/cancelling-selection-change-in-a-bound-wpf-combo-box.aspx
March 30th, 2011 at 2:54 pm
I used the ComboBox.ItemTemplate property to achieve the same goal.
This work fine as well, but your solution is better in my case : I can use the DisplayMemberPath property at the same time !!
Thanks a lot
March 30th, 2011 at 2:57 pm
I almost forget …
There is no need for HorizontalAlignment=”Stretch” IsEnabled=”False” in the Separator (at least with Framework 4.0).
May 5th, 2011 at 12:23 am
It was not obvious at first to me so I want to add for others that you need to specify the binding path that will have your “empty value” as such
Hope that helps
July 4th, 2011 at 5:21 am
“But IMHO I prefer not to have any UI-related stuff in my ViewModel classes”
doesn’t adding a blank item (that consitutes a separator anyway) fail to achieve this?