C#绑定模型问题:如何将MeasureA中所有MeasureB绑定到DataGrid
多层集合合并绑定到DataGrid解决方案
现有模型结构
DataModel 类
public class DataModel : INotifyPropertyChanged { public BindingList<MiddleMeasure> MeasureA { get; set; } public DataModel() { this.MeasureA = new BindingList<MiddleMeasure>() { new MiddleMeasure() { } }; } public event PropertyChangedEventHandler PropertyChanged; void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
MiddleMeasure 类
public class MiddleMeasure { public BindingList<MeasureData> MeasureB { get; set; } = new BindingList<MeasureData>(); public MiddleMeasure() { MeasureB.Add(new MeasureData() { Title = "500", Title2 = 500, Data = 10, }); MeasureB.Add(new MeasureData() { Title = "501", Title2 = 501, Data = 20, }); MeasureB.Add(new MeasureData() { Title = "503", Title2 = 503, Data = 30, }); MeasureB.Add(new MeasureData() { Title = "504", Title2 = 504, Data = 40, }); } }
MeasureData 类
public class MeasureData : INotifyPropertyChanged { private string m_Title; private double m_Title2; private double m_Data; public MeasureData() { } public MeasureData(double title, double data) { this.Title2 = title; this.Title = title.ToString(); this.Data = data; } public string Title { get => this.m_Title; set { this.m_Title = value; OnPropertyChanged(nameof(Title)); } } public double Title2 { get => this.m_Title2; set { this.m_Title2 = value; OnPropertyChanged(nameof(Title2)); } } public double Data { get => this.m_Data; set { this.m_Data = value; OnPropertyChanged(nameof(Data)); } } public event PropertyChangedEventHandler PropertyChanged; void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
问题描述
当前模型为DataModel包含MiddleMeasure集合,每个MiddleMeasure又包含MeasureData集合。直接绑定this.xDataGrid.ItemsSource = this.m_Model.MeasureA无法显示目标数据,仅绑定单个MiddleMeasure的MeasureB能正常显示,需要将所有MeasureA中的MeasureB数据合并后绑定到DataGrid。
解决方案
方案一:LINQ扁平化集合(静态数据场景)
适合数据加载后不会动态增删的场景,用SelectMany直接将多层集合扁平化为单层MeasureData集合,再转为支持绑定的集合类型:
// 合并所有MeasureB数据 var allMeasureData = m_Model.MeasureA .SelectMany(middleItem => middleItem.MeasureB) .ToList(); // 转为ObservableCollection支持UI自动更新(MeasureData已实现INotifyPropertyChanged,数据变更会自动同步) this.xDataGrid.ItemsSource = new ObservableCollection<MeasureData>(allMeasureData);
方案二:自定义自动同步集合(动态数据场景)
如果MeasureA或MeasureB会动态增删元素,需要DataGrid自动同步变更,可创建自定义集合监听原集合的变更事件:
public class MergedMeasureCollection : ObservableCollection<MeasureData> { private readonly BindingList<MiddleMeasure> _sourceMeasureA; public MergedMeasureCollection(BindingList<MiddleMeasure> sourceMeasureA) { _sourceMeasureA = sourceMeasureA; // 初始化加载所有数据 LoadAllData(); // 监听MeasureA的集合变更 _sourceMeasureA.ListChanged += MeasureA_ListChanged; } private void LoadAllData() { Clear(); foreach (var middle in _sourceMeasureA) { foreach (var data in middle.MeasureB) { Add(data); } // 监听当前MiddleMeasure的MeasureB变更 middle.MeasureB.ListChanged += MeasureB_ListChanged; } } private void MeasureA_ListChanged(object sender, ListChangedEventArgs e) { switch (e.ListChangedType) { case ListChangedType.ItemAdded: var newMiddle = _sourceMeasureA[e.NewIndex]; foreach (var data in newMiddle.MeasureB) { Add(data); } newMiddle.MeasureB.ListChanged += MeasureB_ListChanged; break; case ListChangedType.ItemDeleted: var oldMiddle = e.OldIndex >= 0 ? _sourceMeasureA[e.OldIndex] : null; if (oldMiddle != null) { foreach (var data in oldMiddle.MeasureB.ToList()) { Remove(data); } oldMiddle.MeasureB.ListChanged -= MeasureB_ListChanged; } break; case ListChangedType.Reset: LoadAllData(); break; } } private void MeasureB_ListChanged(object sender, ListChangedEventArgs e) { var measureB = sender as BindingList<MeasureData>; if (measureB == null) return; switch (e.ListChangedType) { case ListChangedType.ItemAdded: Add(measureB[e.NewIndex]); break; case ListChangedType.ItemDeleted: Remove(measureB[e.OldIndex]); break; case ListChangedType.ItemChanged: // MeasureData已实现INotifyPropertyChanged,数据变更会自动同步到UI,无需额外处理 break; case ListChangedType.Reset: LoadAllData(); break; } } // 清理事件绑定,避免内存泄漏 public void Dispose() { _sourceMeasureA.ListChanged -= MeasureA_ListChanged; foreach (var middle in _sourceMeasureA) { middle.MeasureB.ListChanged -= MeasureB_ListChanged; } } }
使用方式:
var mergedCollection = new MergedMeasureCollection(m_Model.MeasureA); this.xDataGrid.ItemsSource = mergedCollection; // 在窗口关闭或ViewModel销毁时调用清理方法 // mergedCollection.Dispose();
方案三:WPF CollectionViewSource 用法(静态数据场景)
WPF项目中可通过CollectionViewSource绑定扁平化后的集合:
<!-- 在Window/UserControl的Resources中定义 --> <Window.Resources> <CollectionViewSource x:Key="MergedMeasureSource" /> </Window.Resources>
后台代码设置数据源:
var cvs = (CollectionViewSource)Resources["MergedMeasureSource"]; cvs.Source = m_Model.MeasureA.SelectMany(m => m.MeasureB).ToList(); this.xDataGrid.ItemsSource = cvs.View;
适用场景说明
- 方案一:实现简单,适合数据固定不变的场景。
- 方案二:支持动态数据同步,适合需要实时更新UI的场景。
- 方案三:WPF专属的基础绑定方式,适合静态数据场景,动态数据需额外结合事件监听。
内容的提问来源于stack exchange,提问作者하하파파
相关产品推荐
相关产品推荐

