WPF动态生成DataGrid/ListView展示类表格嵌套数据方案
问题根因
你当前代码所有单元格显示(Collection)是两个问题导致的:
- 列绑定直接指向
Values这个List<ClassB>集合属性,DataGrid默认会直接输出集合类型的默认字符串标识,不会自动取集合内的元素做匹配 - 你的数据结构是按列维度存储的(每个
ClassA对应一列,内部Values存该列所有行的值),但DataGrid默认按行维度绑定数据源,你既没有给DataGrid指定行级数据源,也没有在绑定里指定当前行对应的元素索引,自然无法正确匹配值。
实现方案
核心思路是先对齐行维度,再通过多绑定传入ViewModel实例和当前行索引,按列索引+行索引定位到具体的DisplayValue,同时处理索引越界(无值留空)的场景。
第一步:添加两个必要的值转换器
// 行号转换器:把从0开始的行索引转成从1开始显示的行号 public class RowIndexToNumberConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value is int rowIndex ? rowIndex + 1 : Binding.DoNothing; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } // 单元格值转换器:按列索引、行索引定位具体值,无值返回空字符串 public class GridCellValueConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values.Length < 2 || parameter is not int colIndex) return string.Empty; if (values[0] is ViewModelClass vm && values[1] is int rowIndex) { // 各种越界场景直接返回空 if (colIndex >= vm.Data.Count) return string.Empty; var targetColumn = vm.Data[colIndex]; if (targetColumn.Values == null || rowIndex >= targetColumn.Values.Count) return string.Empty; return targetColumn.Values[rowIndex].DisplayValue ?? string.Empty; } return string.Empty; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
第二步:替换你原来的动态生成列代码
var vm = DataContext as ViewModelClass; if (vm == null || vm.Data == null || vm.Data.Count == 0) return; MyDataGrid.AutoGenerateColumns = false; MyDataGrid.Columns.Clear(); // 计算总行数:取所有列中Values列表的最大长度 int totalRows = vm.Data.Max(col => col.Values?.Count ?? 0); // 给DataGrid指定行数据源:就是0到totalRows-1的索引序列,对应每一行的序号 MyDataGrid.ItemsSource = Enumerable.Range(0, totalRows).ToList(); // 添加首列(行号列) MyDataGrid.Columns.Add(new DataGridTextColumn { Header = "Row", Binding = new Binding(".") { Converter = new RowIndexToNumberConverter() } }); // 逐个添加数据列 for (int colIndex = 0; colIndex < vm.Data.Count; colIndex++) { var columnData = vm.Data[colIndex]; // 多绑定:第一个参数传ViewModel实例,第二个参数传当前行索引 var cellBinding = new MultiBinding { Converter = new GridCellValueConverter(), ConverterParameter = colIndex }; cellBinding.Bindings.Add(new Binding(".") { Source = vm }); cellBinding.Bindings.Add(new Binding(".")); MyDataGrid.Columns.Add(new DataGridTextColumn { Header = columnData.ColumnName, Binding = cellBinding }); }
效果说明
运行后会完全匹配你给出的表格效果:
- 首列显示从1开始的行号
- 后续列头对应每个
ClassA的ColumnName - 单元格按行、列索引匹配对应
ClassB的DisplayValue,无匹配值时自动留空 - 不需要修改你现有的实体类定义,也不需要额外做数据结构转置
内容的提问来源于stack exchange,提问作者h607732
相关产品推荐
相关产品推荐

