【问题标题】:Detect changes in (elements of) a collection bound to a DataGrid to update other collections in WPF (MVVM)检测绑定到 DataGrid 的集合(元素)中的更改以更新 WPF(MVVM)中的其他集合
【发布时间】:2021-07-03 16:11:33
【问题描述】:

响应式 UI 设计:DataGrid 输入自动引起更改 (MVVM)

我正在尝试创建一个简单的应用程序,其中我有一个图表工具,它接受集合作为要绘制的系列。我的计划是有一个输入 DataGrid 绑定到一个可以手动填充的集合。

基于DataGrid 中的值,然后我想同时填充一个不同的集合,该集合代表正在绘制的任何函数的definite integral,换句话说,一个不同的函数显示输入函数之间的区域和 x 轴。

随着DataGrid 的更新,我也想使用 MVVM 来响应更新图表,以显示输入数据和输出数据的变化。

A.应用部分(模型和结构)

我创建了一个包含my implementations so far 的要点。

1。主要部件

简而言之,应用程序具有以下组件:

  • Coordinate<T, U> 具有 X 和 Y 属性(并使用 INotifyPropertyChanged
  • ObservableCollection<Coordinate<double, double>> 用于绘图目的
  • NumericalCalculator 用于执行数值方法

2。转换器

在 WPF 聊天室中,Maverik 建议我可以使用值转换器让 WPF 完成繁重的工作,因此我编写了以下转换器:

  • CoordinateSeriesToStringConverter 将坐标集合转换为字符串,其中所有坐标用逗号分隔
  • FunctionToEquallySpacedConverter 尝试将坐标集合转换为包含一些 n 等间距坐标数的新集合
  • FunctionToIntegralConverter 尝试将输入函数(坐标集合)积分到其两个边界之间的数值积分(目前尚未积分,用于测试目的)

B.我的实际问题:如何检测DataGrid 的项目源元素的变化?

我已经走了价值转换器路线,但事实证明,即使在我绑定的ObservableCollection 的元素上实现了INotifyPropertyChanged,这些更改也不会激活转换器。

我已经从sparedev 得到了一个很好的答案,但我可能会尝试使用不同的方法,但我仍然很好奇如何解决价值转换器问题。我敢肯定,如果我解决了这个问题,这两个选项同样可行。

更新:我尝试过 spadedev 的方法,但即使使用 INotifyPropertyChanged,从 UI 操作 DataGrid 的项目也不会引发任何新事件。添加新行或删除它们会引发CollectionChanged 事件,但不幸的是,仅此一项并不能让我响应地更新绘图。

【问题讨论】:

标签: c# wpf xaml mvvm datagrid


【解决方案1】:

让我们注册 CollectionChanged 事件并更新结果集合,见下文。

    public MainViewModel()
    {
      InputCollection.CollectionChanged += Items_CollectionChanged;
    }

    private void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
      if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
      {
        foreach (var i in e.NewItems)
        {
          var c = i as Coordinate<double, double>;
          ResultCollection.Add(c);
          c.PropertyChanged += Item_PropertyChanged;
        }
      }

      if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
      {
        foreach (var i in e.OldItems)
        {
          var c = i as Coordinate<double, double>;
          ResultCollection.Remove(c);
          c.PropertyChanged += Item_PropertyChanged;
        }
      }
    }

    private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      var c = sender as Coordinate<double, double>;
      Console.WriteLine(c.X + " " + c.Y);
    }

可能是您的 Coordinate 类应该实现 INotifyPropertyChanged 接口。 在设置 X 或 Y 属性时,PropertyChanged 应该被提升。

  public class Coordinate<T, U> : IComparable<Coordinate<T, U>>, INotifyPropertyChanged
    where T : IComparable<T>
    where U : IComparable<U>
  {
    public Coordinate() { }
    public Coordinate(T x, U y)
        => (X, Y) = (x, y);

    public event PropertyChangedEventHandler PropertyChanged;

    private T _X;
    public T X
    {
      get => _X;
      set
      {
        if (value.CompareTo(_X) != 0)
        {
          _X = value;
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(X)));
        }
      }
    }

    private U _Y;
    public U Y
    {
      get => _Y;
      set
      {
        if (value.CompareTo(_Y) != 0)
        {
          _Y = value;
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Y)));
        }
      }
    }
}

【讨论】:

  • 谢谢,我目前正在使用值转换器来在输入 DataGrid 检测到更改时更新相关集合,但接下来我会尝试这种方法!顺便问一下,我如何使用这种方法来检测我的收藏中元素的变化?
  • 我对我的问题添加了一个小更新,我已经尝试过这个实现,但不幸的是我还必须找到一种方法来捕捉编辑后的坐标PropertyChanged。我只能检测到项目来源的CollectionChanged 事件。
  • 您可以扩展 Items_CollectionChanged 函数。在更新每个项目的集合注册 PropertyChanged 事件期间,我更新了示例。
猜你喜欢
  • 2018-07-16
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 2015-01-11
  • 2023-03-07
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
相关资源
最近更新 更多