You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF DataGrid更新ItemsSource后自定义表头未更新的解决方法

问题解决:WPF DataGrid自定义表头未随数据更新同步绑定

问题根源

你的自定义表头中ItemsControl绑定的是DataGridColumnHeadersPresenter的ItemsSource(即DataGrid的Columns集合),但更新PreformDataList时,仅同步了行数据,未同步更新列的Header绑定对象或触发Columns集合的变更通知,导致表头仍绑定旧的视图模型实例。此外,原XAML中ItemsPresenter的Grid.Row设为3属于错误配置(你的Grid仅定义了2行),会导致默认表头显示异常。

解决方案

方案1:同步更新列Header视图模型

重新加载数据时,在后台创建新列的同时,为每个列分配全新的Header视图模型实例,确保DataGrid.Columns集合的变更能通知到表头:

// 清空旧列
dataGrid.Columns.Clear();

// 基于新数据生成列及对应的Header视图模型
foreach (var columnInfo in GetNewColumnInfos()) // 根据新数据获取列配置
{
    var columnHeaderVm = new ColumnHeaderVm
    {
        IsSelectedForPlotting = false,
        CommandPlotColumn = new RelayCommand(() => /* 执行绘图逻辑 */)
    };

    var dataColumn = new DataGridTextColumn
    {
        Header = columnHeaderVm,
        Binding = new Binding(columnInfo.PropertyPath) // 绑定对应数据字段
    };

    dataGrid.Columns.Add(dataColumn);
}

方案2:直接绑定ViewModel中的Header集合

放弃绑定DataGridColumnHeadersPresenter的ItemsSource,改为绑定ViewModel维护的列Header集合,让表头与数据更新完全同步:

修改XAML自定义表头

<Style TargetType="{x:Type DataGridColumnHeadersPresenter}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="30"></RowDefinition>
                        <RowDefinition Height="30"></RowDefinition>
                    </Grid.RowDefinitions>

                    <!-- 绑定ViewModel中的列Header集合 -->
                    <StackPanel Orientation="Horizontal" Grid.Row="0">
                        <ItemsControl 
                            ItemsSource="{Binding DataContext.ColumnHeaderVms, RelativeSource={RelativeSource AncestorType=DataGrid}}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <StackPanel Orientation="Horizontal"/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <ToggleButton x:Name="btPlotHeader"
                                                IsChecked="{Binding IsSelectedForPlotting, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                                Command="{Binding CommandPlotColumn}">
                                    </ToggleButton>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </StackPanel>

                    <!-- 修复默认表头的Row索引 -->
                    <DataGridColumnHeader 
                        x:Name="PART_FillerColumnHeader" 
                        Grid.Row="1"
                        IsHitTestVisible="False" />
                    <ItemsPresenter Grid.Row="1" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

更新ViewModel代码

public class MyVM: BindableBase
{
    private ObservableCollection<PreformDataVM> preformDataList;
    private ObservableCollection<ColumnHeaderVm> columnHeaderVms;

    public MyVM()
    {
        PreformDataList = new ObservableCollection<PreformDataVM>();
        PreformDataListViewSource = new CollectionViewSource { Source = PreformDataList };
        ColumnHeaderVms = new ObservableCollection<ColumnHeaderVm>();
    }

    public CollectionViewSource PreformDataListViewSource { get; private set; }

    public ObservableCollection<PreformDataVM> PreformDataList
    {
        get => preformDataList;
        set => SetProperty(ref preformDataList, value);
    }

    // 新增列Header集合属性
    public ObservableCollection<ColumnHeaderVm> ColumnHeaderVms
    {
        get => columnHeaderVms;
        set => SetProperty(ref columnHeaderVms, value);
    }

    // 数据刷新方法
    public void RefreshData(IEnumerable<PreformDataVM> newData)
    {
        // 更新行数据
        PreformDataList.Clear();
        foreach (var item in newData) PreformDataList.Add(item);

        // 同步更新列Header视图模型
        ColumnHeaderVms.Clear();
        foreach (var columnInfo in GetColumnInfosFromNewData(newData))
        {
            ColumnHeaderVms.Add(new ColumnHeaderVm
            {
                IsSelectedForPlotting = false,
                CommandPlotColumn = new RelayCommand(() => /* 绘图逻辑 */)
            });
        }

        // 同步创建DataGrid列(按需)
        RefreshDataGridColumns();
    }

    private void RefreshDataGridColumns()
    {
        // 此处编写列创建逻辑,与方案1类似
    }
}

// 列Header视图模型
public class ColumnHeaderVm : BindableBase
{
    private bool isSelectedForPlotting;
    public bool IsSelectedForPlotting
    {
        get => isSelectedForPlotting;
        set => SetProperty(ref isSelectedForPlotting, value);
    }

    public ICommand CommandPlotColumn { get; set; }
}

方案3:强制刷新表头模板(临时方案)

若不想修改绑定逻辑,可在数据更新后强制重新应用表头模板,触发绑定更新:

// 数据更新完成后调用
var presenter = dataGrid.Template.FindName("PART_ColumnHeadersPresenter", dataGrid) as DataGridColumnHeadersPresenter;
if (presenter != null)
{
    presenter.Template = null;
    presenter.ApplyTemplate();
}

关键注意事项

  • 所有视图模型必须继承BindableBase或实现INotifyPropertyChanged,确保属性变更能触发UI更新。
  • 替换PreformDataList时,必须同步更新关联的列Header数据或重新创建列,否则表头绑定对象不会变更。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 18:24:58