You need to enable JavaScript to run this app. WPF 单DataGrid实现双层表头:顶层带排序、下层放搜索框
优惠活动
大模型
产品
解决方案
定价
更多

WPF 单DataGrid实现双层表头:顶层带排序、下层放搜索框

单DataGrid实现双层表头(列标题+搜索栏)方案

原有双Grid方案的核心问题

  • 独立拆分的两个DataGrid排序状态完全不互通:上层只放列标题的DataGrid未绑定实际业务数据源,列对象没有关联排序属性路径,点击表头自然无法触发排序逻辑
  • 双Grid布局需要手动对齐列宽、边距、滚动位置,窗口缩放时极易出现列错位的问题,维护成本极高
  • 要实现排序交互在上层表头的效果,本质上绕不开“列头所在的DataGrid必须绑定实际可排序的数据源”这个前提

优化实现思路

完全取消双Grid叠加的布局,仅保留1个绑定实际业务数据的DataGrid,在每个列的HeaderTemplate内实现纵向双层结构:

  • 第一层放置列标题文本,完全保留DataGrid原生的列头点击排序交互,不需要额外写排序事件
  • 第二层放置对应列的搜索TextBox,搜索框本身会拦截自身区域的鼠标输入事件,不会影响周围列标题区域的排序触发

修正后的代码实现

XAML布局

<Grid>
    <DataGrid 
        x:Name="gridd"
        AutoGenerateColumns="False"
        Margin="93.195,102.655,0,0"
        CanUserSortColumns="True"
        RowHeaderWidth="0">

        <DataGrid.Resources>
            <!-- 沿用原有表头视觉样式 -->
            <Style TargetType="{x:Type DataGridColumnHeader}">
                <Setter Property="Background" Value="Gray"/>
                <Setter Property="Foreground" Value="White"/>
                <Setter Property="BorderThickness" Value="0,0,1,0" />
                <Setter Property="BorderBrush" Value="White"/>
                <Setter Property="Padding" Value="5 0 0 0"/>
                <Setter Property="Height" Value="Auto"/>
            </Style>
        </DataGrid.Resources>

        <DataGrid.Columns>
            <DataGridTextColumn 
                Width="*" 
                Binding="{Binding Id}"
                SortMemberPath="Id">
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="Artikelnummer" FontSize="10"/>
                            <TextBox x:Name="SearchBox_Id" Margin="0,4,0,0"/>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>

            <DataGridTextColumn 
                Width="*" 
                Binding="{Binding Name}"
                SortMemberPath="Name">
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="Artikelnummer" FontSize="10"/>
                            <TextBox x:Name="SearchBox_Name" Margin="0,4,0,0"/>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>

            <DataGridTextColumn 
                Width="*" 
                Binding="{Binding Birthday}"
                SortMemberPath="Birthday">
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="Matchcode" FontSize="10"/>
                            <TextBox x:Name="SearchBox_Birthday" Margin="0,4,0,0"/>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>

            <DataGridTextColumn 
                Width="*" 
                Binding="{Binding ort}"
                SortMemberPath="ort">
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="Hersteller" FontSize="10"/>
                            <TextBox x:Name="SearchBox_Ort" Margin="0,4,0,0"/>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>

            <DataGridCheckBoxColumn 
                Width="*" 
                Binding="{Binding IsSelected}"
                SortMemberPath="IsSelected">
                <DataGridCheckBoxColumn.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="CheckBox" FontSize="10"/>
                            <TextBox x:Name="SearchBox_Check" Margin="0,4,0,0"/>
                        </StackPanel>
                    </DataTemplate>
                </DataGridCheckBoxColumn.HeaderTemplate>
            </DataGridCheckBoxColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

后台C#逻辑

public MainWindow()
{
    InitializeComponent();

    List<User> users = new List<User>
    {
        new User() { Id = 1, Name = "John Doe", ort="Berlin", Birthday = new DateTime(1971, 7, 23), alter=18, IsSelected = false },
        new User() { Id = 2, Name = "Jane Doe", ort = "Köln", Birthday = new DateTime(1974, 1, 17), alter = 28, IsSelected = true },
        new User() { Id = 3, Name = "Sammy Doe", ort = "Bayern", Birthday = new DateTime(1991, 9, 2), alter = 38, IsSelected = false }
    };

    // 用CollectionViewSource包装数据源,保证排序、过滤状态正常生效
    CollectionViewSource viewSource = new CollectionViewSource();
    viewSource.Source = users;
    gridd.ItemsSource = viewSource.View;
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string ort { get; set; }
    public DateTime Birthday { get; set; }
    public int alter { get; set; }
    public bool IsSelected { get; set; }
}

落地注意事项

  • 不需要额外编写排序触发代码:点击列标题区域会自动触发对应列的升/降序切换,原生的排序方向箭头会正常显示
  • 列宽完全自动适配窗口大小,不存在双Grid的列错位问题
  • 后续扩展列级搜索时,只需要给每个TextBox绑定TextChanged事件,通过当前DataGrid的CollectionView添加过滤规则即可,不需要调整布局结构

内容的提问来源于stack exchange,提问作者user15530832

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 07:36:08