WPF带表头多列ComboBox实现问题:已实现搜索过滤,无法显示多列表头
解决WPF带表头的多列FilteredComboBox问题
嗨,你已经搞定了包含式搜索的FilteredComboBox,卡在多列表头这块太正常了——WPF原生ComboBox的下拉框默认压根不带表头,得从控件模板入手改造才行。我给你一步步捋清楚解决方案:
1. 先把多列的ItemTemplate捋顺
首先确保你的SearchGridTemplate(也就是ItemTemplate)是正确的多列布局,比如用Grid来定义每一行的列结构:
<DataTemplate x:Key="SearchGridTemplate"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100" SharedSizeGroup="IdCol"/> <ColumnDefinition Width="*" SharedSizeGroup="DescCol"/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding Id}" Grid.Column="0" Padding="5"/> <TextBlock Text="{Binding Description}" Grid.Column="1" Padding="5"/> </Grid> </DataTemplate>
这里加SharedSizeGroup是为了后面表头和内容列宽自动对齐,不用手动调宽度。
2. 重写ComboBox的ControlTemplate,加入表头
原生ComboBox的下拉框是Popup套ScrollViewer+ItemsPresenter,我们要在ItemsPresenter上方插入一个表头行,和ItemTemplate的列完全对应。给你的FilteredComboBox写一个带表头的ControlTemplate:
<ControlTemplate x:Key="FilteredComboBoxWithHeaderTemplate" TargetType="wpf:FilteredComboBox"> <Grid> <!-- 保留原生ComboBox的切换按钮、输入框等基础元素 --> <ToggleButton x:Name="toggleButton" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" Margin="0" Padding="0" Background="Transparent" BorderBrush="Transparent"/> <ContentPresenter x:Name="contentPresenter" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" Margin="3,3,23,3" VerticalAlignment="Center"/> <TextBox x:Name="PART_EditableTextBox" Style="{x:Null}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,3,23,3" Focusable="True" Background="Transparent" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}"/> <!-- 改造下拉Popup,加入表头 --> <Popup x:Name="PART_Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" PopupAnimation="Slide"> <Grid x:Name="DropDownContainer" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}"> <Border BorderThickness="1" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/> <!-- 表头行,和ItemTemplate列共享尺寸组 --> <Grid Grid.Row="0" Background="#F0F0F0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="100" SharedSizeGroup="IdCol"/> <ColumnDefinition Width="*" SharedSizeGroup="DescCol"/> </Grid.ColumnDefinitions> <TextBlock Text="ID" Grid.Column="0" FontWeight="Bold" Padding="5"/> <TextBlock Text="描述" Grid.Column="1" FontWeight="Bold" Padding="5"/> </Grid> <!-- 原来的列表内容放在表头下方 --> <ScrollViewer Grid.Row="1" Margin="0,2,0,0" SnapsToDevicePixels="True"> <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </ScrollViewer> </Grid> </Popup> </Grid> <!-- 保留原生的触发器逻辑 --> <ControlTemplate.Triggers> <Trigger Property="HasItems" Value="false"> <Setter TargetName="DropDownContainer" Property="MinHeight" Value="95"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> </Trigger> <Trigger SourceName="PART_EditableTextBox" Property="IsVisible" Value="true"> <Setter TargetName="contentPresenter" Property="Visibility" Value="Hidden"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
3. 把模板应用到你的FilteredComboBox上
最后把这个带表头的模板绑定到你的控件上,同时关联之前的多列ItemTemplate:
<wpf:FilteredComboBox DisplayMemberPath="Description" IsEditable="True" IsTextSearchEnabled="False" ItemTemplate="{StaticResource SearchGridTemplate}" Template="{StaticResource FilteredComboBoxWithHeaderTemplate}"/>
额外小提示
- 如果你的列需要自适应内容,可以把
SharedSizeGroup保留,去掉固定宽度,这样表头和内容列会自动匹配最宽的内容宽度。 - 要是觉得用Grid做表头不够灵活,也可以直接把下拉内容换成
DataGrid(把ItemTemplate换成DataGrid的模板),DataGrid自带表头,还支持排序,但要注意调整DataGrid的样式,去掉多余的边框和滚动条,适配ComboBox的下拉框尺寸。
这样改完之后,下拉框就能显示带表头的多列内容,同时保留你之前实现的包含式搜索过滤功能啦。
内容的提问来源于stack exchange,提问作者Vinay
相关产品推荐
相关产品推荐

