A simple Multiselect ComboBox using expression Blend



I have often seen requirements to have a combobox with multiple selection enabled. We know thatWPF ListBox control is having two special properties, which enables the multiple selection but the combobox doesnt have those
public IList SelectedItems { get; }
public SelectionMode SelectionMode { get; set; }
There are many ways we can make a multiselect combo box
1)Create a custom control from the scratch and have a Listbox in the dropdown
2)Extend the combobox and add the above properties to it
3)Edit the Combobox control template to add necessary controls and binding.

I am going to describe the 3rd idea from the above list, which is a total Expression Blend work, so no need of VS2008 to make a multiselect combobox from a simple combobox.

Place a combobox in to the editing area and right click on the control to create an copy of the Control template. Now you can see the Control's tree on the left side of Expression Blend



The ItemPresenter inside the scrollviewer is actually the control which displays the data in the dropdown part of the combobox, we want to havethe multiselection enabled on that. So replace the ItemsPresenter with a ListBox control with SelectionMode=Multiple 
The last control in the tree, ContentPresenter is to show the selectedvalue in the combobox's main area. Since we are going to have more than one value from the ListBox we need to have an ItemsPresenter like control here. Just for simplicity I have replace it with an ItemsControl with a an ItemsPanel as StackPanel with horizontal orientation.
Now we need to bind the ListBox.SelectedItems to the ItemsControl using an ElementName binding.



<Style x:Key="MultiSelectComboBox" TargetType="{x:Type ComboBox}">

<Setter Property="Template">

<Setter.Value>

<ControlTemplate TargetType="{x:Type ComboBox}">

<Grid SnapsToDevicePixels="true" x:Name="MainGrid" Height="Auto" Width="Auto">

<Grid.ColumnDefinitions>

<ColumnDefinition Width="*"/>

<ColumnDefinition Width="0"/>

</Grid.ColumnDefinitions>

<Popup AllowsTransparency="true" IsOpen="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"

Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}"

Margin="1" x:Name="PART_Popup" Grid.ColumnSpan="2">

<Border x:Name="DropDownBorder" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding Path=ActualWidth, ElementName=MainGrid}">

<ScrollViewer CanContentScroll="true">

<ListBox x:Name="lstBox" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"

KeyboardNavigation.DirectionalNavigation="Contained" SelectionMode="Multiple" ItemsSource="{TemplateBinding ItemsSource}"/>

</ScrollViewer>

</Border>

</Popup>

<ToggleButton Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Grid.ColumnSpan="2"

  IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Style="{DynamicResource ToggleButtonStyle1}"/>

<ItemsControl IsHitTestVisible="false" ItemsSource="{Binding Path=SelectedItems, ElementName=lstBox}" Margin="4,0,0,0">

<ItemsControl.ItemsPanel>

<ItemsPanelTemplate>

<StackPanel IsItemsHost="True" Orientation="Horizontal"/>

</ItemsPanelTemplate>

</ItemsControl.ItemsPanel>

</ItemsControl>

</Grid>

</ControlTemplate>

</Setter.Value>

</Setter>

</Style>


Now we need to access the SelectedItems from this new control template. Use the bellow line
((ListBox)cmbBox.Template.FindName("lstBox",cmbBox)).SelectedItems
You can download the sample project here

Comments

Anonymous said…
Interesting post, I've been trying to do a similar thing with a hierarchical TreeView without success. Any thoughts on how someone might create a multi-select hierarchical TreeView?
Paras said…
Hey, Very Interesting Post. I was looking for the same. Thank.

But I have some problem now. How do I select values from c# code?
Unknown said…
Interesting work!
Only one point, it's not working for a silverlight app.

Could you please providesome hints for a silverlight version.
KSR said…
Hi ,

Thanks for this interresting article.

Your post was very helpful for my requirement.

I need some help regarding selected text.

How can i add display separator(,) to multiple selected items.

Please revert back your comments.

Thanks In Advance.

Popular posts from this blog

Time Picker User Control

A Simple Radial Panel for WPF and SilverLight