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

WPF DataGrid中如何为动态创建的列实现数据绑定?

WPF DataGrid动态绑定自定义属性列实现方案

核心实现思路

通过给PointViewModel添加索引器支持,结合DataGrid动态列生成,实现自定义属性的双向绑定编辑。

1. 完善ViewModel定义

确保所有ViewModel实现INotifyPropertyChanged,并给PointViewModel添加索引器,用于通过属性名快速定位自定义属性项:

public class PointCustomPropViewModel : INotifyPropertyChanged
{
    private string _propName;
    private string _propValue;

    public string PropName
    {
        get => _propName;
        set
        {
            if (_propName != value)
            {
                _propName = value;
                OnPropertyChanged();
            }
        }
    }

    public string PropValue
    {
        get => _propValue;
        set
        {
            if (_propValue != value)
            {
                _propValue = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class PointViewModel : INotifyPropertyChanged
{
    // 核心属性
    public string Name { get; set; }
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }

    public ObservableCollection<PointCustomPropViewModel> CustomProperties { get; } = new();

    // 索引器:通过属性名获取对应自定义属性项
    public PointCustomPropViewModel this[string propName]
    {
        get => CustomProperties.FirstOrDefault(p => p.PropName == propName);
        set
        {
            var existing = CustomProperties.FirstOrDefault(p => p.PropName == propName);
            if (existing != null)
            {
                existing.PropValue = value.PropValue;
            }
            else
            {
                CustomProperties.Add(value);
            }
            OnPropertyChanged(nameof(CustomProperties));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. DataGrid XAML配置

先固定核心属性列,关闭自动生成列:

<DataGrid x:Name="PointDataGrid" 
          ItemsSource="{Binding TestPoints}" 
          AutoGenerateColumns="False">
    <!-- 核心属性固定列 -->
    <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
    <DataGridTextColumn Header="X" Binding="{Binding X}" />
    <DataGridTextColumn Header="Y" Binding="{Binding Y}" />
    <DataGridTextColumn Header="Z" Binding="{Binding Z}" />
</DataGrid>

3. 动态生成自定义属性列

在窗口/对话框的Loaded事件中,遍历自定义属性名并生成可编辑列:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    if (DataContext is MainViewModel vm && vm.TestPoints.Any())
    {
        // 收集所有唯一的自定义属性名(兼容不同点属性不一致的情况)
        var allPropNames = vm.TestPoints
            .SelectMany(p => p.CustomProperties.Select(cp => cp.PropName))
            .Distinct();

        foreach (var propName in allPropNames)
        {
            var customColumn = new DataGridTextColumn
            {
                Header = propName,
                // 通过索引器绑定对应属性的PropValue,开启双向同步
                Binding = new Binding($"CustomProperties[{propName}].PropValue")
                {
                    Mode = BindingMode.TwoWay,
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                }
            };
            PointDataGrid.Columns.Add(customColumn);
        }
    }
}

4. 测试数据示例

在主ViewModel中生成测试集合:

public class MainViewModel : INotifyPropertyChanged
{
    public ObservableCollection<PointViewModel> TestPoints { get; } = new();

    public MainViewModel()
    {
        var rnd = new Random();
        for (int i = 0; i < 5; i++)
        {
            var point = new PointViewModel
            {
                Name = $"Point_{i}",
                X = rnd.NextDouble() * 100,
                Y = rnd.NextDouble() * 100,
                Z = rnd.NextDouble() * 100
            };
            // 添加自定义属性
            point.CustomProperties.Add(new PointCustomPropViewModel { PropName = "Color", PropValue = $"#{rnd.Next(0x1000000):X6}" });
            point.CustomProperties.Add(new PointCustomPropViewModel { PropName = "Weight", PropValue = rnd.Next(10, 50).ToString() });
            TestPoints.Add(point);
        }
    }

    // INotifyPropertyChanged实现...
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

关键注意事项

  • 若不同点的自定义属性不一致,需通过SelectMany收集所有唯一属性名,避免遗漏列
  • 索引器绑定是实现动态列双向编辑的核心,确保编辑单元格时直接更新对应PointCustomPropViewModel的PropValue
  • 所有ViewModel必须实现INotifyPropertyChanged,保证数据更新时UI同步

内容的提问来源于stack exchange,提问作者5ORBEX

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 04:43:27