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

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,提问作者하하파파

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:07:22