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)).SelectedItemsYou can download the sample project here
No comments:
Post a Comment
Send us your comment related to the topic mentioned on the blog