Is it possible to have "column headers" on a combo box bound to multiple items? For example a combo box that displays a persons name. The combo box would display John Doe. But I'd like to display column headers:
First Last
John Doe
Jane Doe
Jimmy Doe
Is this possible without the use of a data grid? What about a simple solution that includes the use of a data grid? I found one solution for embedding a data grid into a combo box but it looks difficult and requires MS Blend.
I'd be happy if I could just get some headers as the first row in the drop down.
G
Here is my xaml code with HB's attempt that produces a compile error as mentioned in the comments.
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
<ComboBox Name="cboPlaceNames" Grid.IsSharedSizeScope="True" ItemsSource="{DynamicResource items}" Height="22" Width="285" Margin="0,6,165,0" SelectedIndex="0" HorizontalAlignment="Right" VerticalAlignment="Top" SelectionChanged="cboPlaceNames_SelectionChanged">
<ComboBox.Resources>
<CompositeCollection x:Key="items">
<ComboBoxItem IsEnabled="False">
<Grid TextElement.FontWeight="Bold">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition SharedSizeGroup="B"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition SharedSizeGroup="C"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Grid.Column="0" Text="Name"/>
<TextBlock Grid.Column="2" Text="CLLI"/>
<TextBlock Grid.Column="4" Text="Street"/>
</Grid.Children>
</Grid>
</ComboBoxItem>
<Separator/>
<CollectionContainer Collection="{Binding Source={x:Reference cboPlaceNames}, Path=DataContext.Data}"/>
</CompositeCollection>
<DataTemplate DataType="x:Type obj:PlaceName">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition SharedSizeGroup="B"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition SharedSizeGroup="C"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Grid.Column="0" Text="{Binding Name}"/>
<TextBlock Grid.Column="2" Text="{Binding CLLI}"/>
<TextBlock Grid.Column="4" Text="{Binding Street}"/>
</Grid.Children>
</Grid>
</DataTemplate>
</ComboBox.Resources>
</ComboBox>
I liked Nandha's answer because this was what I was trying to achieve. However, the text field of the combo box will not work correctly.
Since I am lazy, to get around this I created a StackPanel of Horizontal orientation, with a TextBox bound to a field from the selected item, and the Combo Box with the embedded ListView. The Combo Box now has a width of 20 so just the down arrow shows (you can play with the width and margins to get just the right look. This makes the text box look like a combo box, with all the benefits of the ListView, and much less coding.
I hope this helps.enter image description here
Example:
<ComboBox Name="cb" Grid.IsSharedSizeScope="True" ItemsSource="{DynamicResource items}">
<ComboBox.Resources>
<CompositeCollection x:Key="items">
<ComboBoxItem IsEnabled="False">
<Grid TextElement.FontWeight="Bold">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Grid.Column="0" Text="Name"/>
<TextBlock Grid.Column="2" Text="Occupation"/>
</Grid.Children>
</Grid>
</ComboBoxItem>
<Separator/>
<CollectionContainer Collection="{Binding Source={x:Reference cb}, Path=DataContext.Data}"/>
</CompositeCollection>
<DataTemplate DataType="{x:Type obj:Employee}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Grid.Column="0" Text="{Binding Name}"/>
<TextBlock Grid.Column="2" Text="{Binding Occupation}"/>
</Grid.Children>
</Grid>
</DataTemplate>
</ComboBox.Resources>
</ComboBox>
Note that getting the Collection
-binding right is not that easy because there is neither DataContext
nor VisualTree to rely on, ElementName
and RelativeSource
does not work, this is because CompositeCollection
is just a collection, not a FrameworkElement.
Other than that the way this is done is via Grids that have shared size columns. The DataTemplate is applied automatically via the DataType
.
Edit: Setting the header-ComboBoxItem's IsHitTestVisible
property to False
is not enough since it still can be selected using the keyboard. I now changed it to IsEnabled="False"
which fades out the item a bit. You could probably re-template that item to not do that. Or if you find another way of disabling it from selection that would of course work out too.
The simplest way to add columns headers to combobox is to use listview in combobox. The following code is give the solution to it.
<ComboBox HorizontalAlignment="Center"
IsTextSearchEnabled="False" Width="200"
IsEditable="True" Text="{Binding }">
<ListView ItemsSource="{Binding YOURITEMSOURCE}"
SelectedItem="{Binding Path=SELECTEDITEMSOURCE}"
Height="200" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.View>
<GridView>
<GridViewColumn Width="130" Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Width="130" Header="Occupation" DisplayMemberBinding="{Binding Occupation}" />
<GridViewColumn Width="130" Header="Age" DisplayMemberBinding="{Binding Age}" />
<GridViewColumn Width="130" Header="Salary" DisplayMemberBinding="{Binding Salary}" />
</GridView>
</ListView.View>
</ListView>
</ComboBox>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With