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
相关产品推荐
相关产品推荐

