Introduction
ComboBox
is a widely used control. Sometimes, we want to go beyond its default capability, such as multiple-selection. In this article, I will walk through with you how to create a multiple-selection ComboBox
for Silverlight. The same approach applies to WPF. I will use Expression Blend for design. It is efficient to use the Blend to create a resource skeleton; and you can use either Blend or Visual Studio to edit the code.
In this updated version, I answered the most asked question: How to display the selected items?
Step by Step
The goal is to create a multiple-selection ComboBox
as shown in the left side of following figure. The items in the dropdown should display with CheckBox
es. The right side ListBox
demonstrates the same XAML code can be used for a multiple selection ListBox
. One stone kills two birds!
Assume you have a ComboBox
in place, and want to make it supporting multiple-selection. First, right-click the ComboBox
to popup the context menu. In the menu, select Edit Template -> Edit a Copy. This will open the Create Style Resource dialog box. You can rename the default Name (Key) in the dialog. And then click OK to close the dialog.
Now you get the default template of the ComboBox
in your .xaml file. You can browse the details in the following window, and figure out how the ComboBox
works: when you click the ComboBox
, it pops up a Popup
control. By default, the Popup
control uses an ItemsPresenter
to display the SourceItems
of the ComboBox
. We need to replace it with a ListBox
which supports multiple-selection.
Tips
- The Windows theme setting will effect on the Blend generated template. I suggest you avoid Basic Themes.
- The Blend generated template could be slightly different with different versions of Silverlight. If you cannot make the
ComboBox
template generated with Silverlight 3 work with Silverlight 4, regenerate it Silverlight 4.
We also need to the replace the ListBoxItem
with CheckBox
so that the user can easily identify the selection status. It would be efficient to do this in the XAML window. Let’s create the CheckBoxListBoxItemStyle
style as follows:
<Style x:Key="CheckBoxListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Foreground" Value="#FF000000" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid x:Name="RootElement">
<CheckBox ClickMode="Press" Content="{Binding Path=Name}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Make sure you set ClickMode="Press";
and Mode=TwoWay
.
The data I am using here is very simple: a Name
property, and an IsSelected
property.
Set the ItemContainerStyle
in the ListBox
to the CheckBoxListBoxItemStyle
as follows:
<ListBox x:Name="lstBox" SelectionMode="Multiple"
ItemsSource="{TemplateBinding ItemsSource}"
ItemContainerStyle="{StaticResource CheckBoxListBoxItemStyle}"
HorizontalAlignment="Stretch" />
Now you can build and run the project. In the demo page, I included an additional ListBox
, which is bound to the same data. The ListBox
reuses the same style CheckBoxListBoxItemStyle
. With the ListBox
, you can validate that the selection is updated on both the ComboBox
and the ListBox
.
Now it’s time to create a Resource Dictionary file, and move the resource (templates and styles) to the Resource Dictionary.
It seems ambiguous to display the selected items in the collapsed ComboBox
, which is designed to display a single item. Here we need the creativity of the User Interface design. For instance, we can reduce the width of the ComboBox
, and use a separate ItemsControl
to display the selected items. The ItemsControl
binds to the same data as ComboBox
, but displays selected items only. We can implement a converter class with IValueConverter
to convert the IsSelected bool
property to Visibility
. In this way, the ItemsControl
displays selected items only.
<ItemsControl ItemsSource="{Binding Data}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"
Visibility="{Binding IsSelected,
Converter={StaticResource BoolToVisibilityConverter}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Further, we can use the Tooltip
to display the selected items. The following figure shows the Tooltip
with an ItemsControl
embedded within.
Following is the code snippet for how to embed an ItemsControl
in the Tooltip
:
<ComboBox ItemsSource="{Binding Data}" Width="26" VerticalAlignment="Center"
Style="{StaticResource MultiSelComboBoxStyle}" >
<ToolTipService.ToolTip>
<ToolTip>
<ItemsControl ItemsSource="{Binding Data}" Margin="4" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"
Visibility="{Binding IsSelected,
Converter={StaticResource BoolToVisibilityConverter}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ToolTip>
</ToolTipService.ToolTip>
</ComboBox>
Conclusion
The ComboBox
contains a Popup
control for hosting the item selection control. You can replace the default one to customize the behavior, such as multiple selection. Technically, you can embed a UserControl
(or almost any control) in the Popup
control. This opens the door for creating more sophisticated User Interface. For detail. please read How to Popup Anything?