如何用UserControl为外层DataGrid的RowDetails绑定不同InnerDataGrid
问题根源在于你当前的InnerDataGrid绑定的是外层DataGrid全局DataContext中的DetailsTable,所有行的RowDetails共享同一个数据源,所以打开新行时会覆盖已有数据。要解决这个问题,核心是让外层DataGrid的每一行数据对象本身持有独立的明细数据表,并让InnerDataGrid绑定到当前行的明细属性。
步骤1:修改外层数据模型
给外层DataGrid的每行数据对象(假设类名为OuterRowItem)添加一个独立的明细数据表属性,确保每个实例持有自己的DataTable,并实现INotifyPropertyChanged:
public class OuterRowItem : INotifyPropertyChanged { // 原有的外层表字段属性... // 新增:当前行对应的明细数据表 private DataTable _innerDetailsTable; public DataTable InnerDetailsTable { get => _innerDetailsTable; set { _innerDetailsTable = value; OnPropertyChanged(nameof(InnerDetailsTable)); } } // INotifyPropertyChanged 实现 public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
步骤2:调整InnerDgUserControl的绑定
修改InnerDgUserControl的XAML,让InnerDataGrid绑定到当前行数据对象的InnerDetailsTable(此时UserControl的DataContext就是外层行的OuterRowItem实例):
<Grid> <DataGrid x:Name="innerDg" ItemsSource="{Binding InnerDetailsTable.DefaultView}" AutoGenerateColumns="True" IsReadOnly="False" CanUserAddRows="False" CanUserReorderColumns="False" EnableColumnVirtualization="True" EnableRowVirtualization="True" MaxWidth="2560" MaxHeight="2000" RowHeight="20" VirtualizingStackPanel.VirtualizationMode="Standard"> </DataGrid> </Grid>
步骤3:加载行对应的明细数据
在外层DataGrid的行数据初始化/加载时,为每个OuterRowItem的InnerDetailsTable赋值对应的明细数据(比如从数据库、文件或其他数据源获取当前行专属的DataTable):
// 示例:外层数据加载时,为每行绑定对应明细 foreach (var outerItem in outerTableItems) { // 根据当前行的标识获取对应的明细DataTable var innerTable = GetInnerDataTableForOuterItem(outerItem.Id); outerItem.InnerDetailsTable = innerTable; }
关键说明
- 每个
OuterRowItem的InnerDetailsTable必须是独立的DataTable实例,不能多个行共享同一个对象,否则仍会出现数据覆盖问题。 - 因为你已经实现了
INotifyPropertyChanged,当InnerDetailsTable异步加载完成后,UI会自动更新对应的InnerDataGrid。 - 动态生成DataGrid的需求完全兼容:
AutoGenerateColumns="True"会自动根据DataTable的结构生成列,无需提前知道行列数。
原代码问题分析
你之前的InnerDataGrid绑定路径{Binding DataContext.DetailsTable.DefaultView, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}},是获取外层DataGrid的全局DataContext中的DetailsTable,这是一个单一实例,所有行的RowDetails都会绑定到同一个数据源,所以打开新行更新这个属性时,所有已展开的详情都会同步变化。
内容的提问来源于stack exchange,提问作者nicwen

