1

我有一个ObservableCollection<Data> Items

数据上有一个“列”属性,它又是一个ObservableCollection<Column>.

Column 对象有一个名为“IsActive”的布尔属性。

我有一个案例,我需要确定是否所有“项目”都具有“列”属性,如果是,则所有列都应该将“IsActive”设置为真或假,但不能同时具有两者。

诀窍是我需要将此逻辑放在按钮的 CanExecute 中。我需要使其尽可能高效和快速...有什么想法吗?结构是:

public class MyClass
{
     public ObservableCollection<Data> Items
    {
         get{return _items;}
     }
}

public class Data
{
    public ObservableCollection<Column> Columns
    {
         get{return _columns;}
     }
}

public class Column
{

   public bool IsActive{ get; set;}

}

谢谢!

4

1 回答 1

2

这闻起来像是过早的优化。你测量过简单方法的速度吗?在现代 CPU 上迭代几个不太大的集合只需要几毫秒。

如果您想使用 LINQ 计算所有Column对象是活动的还是非活动的,您可以使用此表达式。

public Boolean CanExecute {
  get {
    var aggregate = Items
      .SelectMany(i => i.Columns)
      .Aggregate(
        new {
          IsEmpty = true,
          AllAreActive = true,
          AllAreInactive = true
        },
        (a, c) => new {
          IsEmpty = false,
          AllAreActive = a.AllAreActive && c.IsActive,
          AllAreInactive = a.AllAreInactive && !c.IsActive
        }
    );
    return !aggregate.IsEmpty && (aggregate.AllAreActive || aggregate.AllAreInactive);
  }

此代码将遍历所有集合中的所有元素。您可以通过使用for循环并在两个布尔变量都变为假时打破它来改进这一点。这也可以通过TakeWhile使用具有副作用的谓词在 LINQ 中完成,但简单的for循环可能更容易理解。

如果您认为简单的方法太慢,您需要跟踪该级别的CanExecute属性。您可以通过为所有实例MyClass设置更改通知处理程序来做到这一点。ObservableCollection这有点乏味,因为您有两个级别的集合,但它将确保每当Column从集合中添加或删除 a 或更改属性时,都会更新支持的IsActive布尔变量。CanExecuteMyClass

最初Column必须实施INotifyPropertyChanged

class Column : INotifyPropertyChanged {

  Boolean isActive;

  public Boolean IsActive {
    get { return this.isActive; }
    set {
      if (this.isActive == value)
        return;
      this.isActive = value;
      OnPropertyChanged("IsActive");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  protected void OnPropertyChanged(String propertyName) {
    var handler = PropertyChanged;
    if (handler != null)
      handler(this, new PropertyChangedEventArgs(propertyName));
  }

}

Data必须公开所需的属性,由于缺少更好的名称,我已经调用AllColumnsAreActiveOrInactive了该属性,并且通过实现来表示对该属性的更改INotifyPropertyChanged

为了跟踪所有列的状态,CollectionChanged集合Column的处理。当Column添加一个新的值时,AllColumnsAreActiveOrInactive可以重新计算而不迭代Column集合。但是,当IsActive一个单一的变化Column或当一个Column被删除时,集合必须被迭代以确定新的值AllColumnsAreActiveOrInactive

class Data : INotifyPropertyChanged {

  readonly ObservableCollection<Column> columns;

  Boolean allColumnsAreActive = true;

  Boolean allColumnsAreInactive = true;

  Boolean allColumnsAreActiveOrInactive = false;

  public Data() {
    this.columns = new ObservableCollection<Column>();
    this.columns.CollectionChanged += CollectionChanged;
  }

  public ObservableCollection<Column> Columns { get { return this.columns; } }

  public Boolean AllColumnsAreActiveOrInactive {
    get { return this.allColumnsAreActiveOrInactive; }
    set {
      if (value == this.allColumnsAreActiveOrInactive)
        return;
      this.allColumnsAreActiveOrInactive = value;
      OnPropertyChanged("AllColumnsAreActiveOrInactive");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  protected void OnPropertyChanged(String propertyName) {
    var handler = PropertyChanged;
    if (handler != null)
      handler(this, new PropertyChangedEventArgs(propertyName));
  }

  void CollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) {
    if (e.Action == NotifyCollectionChangedAction.Reset) {
      RecomputeAllColumnsAreActiveOrInactive();
      return;
    }
    if (e.OldItems != null) {
      foreach (var item in e.OldItems.Cast<Column>())
        item.PropertyChanged -= ColumnPropertyChanged;
      RecomputeAllColumnsAreActiveOrInactive();
      return;
    }
    if (e.NewItems != null) {
      foreach (var column in e.NewItems.Cast<Column>()) {
        column.PropertyChanged += ColumnPropertyChanged;
        this.allColumnsAreActive = this.allColumnsAreActive && column.IsActive;
        this.allColumnsAreInactive = this.allColumnsAreInactive && !column.IsActive;
      }
      UpdateAllColumnsAreActiveOrInactive();
    }
  }

  void ColumnPropertyChanged(Object sender, PropertyChangedEventArgs e) {
    if (e.PropertyName == "IsActive") {
      var column = sender as Column;
      RecomputeAllColumnsAreActiveOrInactive();
    }
  }

  void RecomputeAllColumnsAreActiveOrInactive() {
    this.allColumnsAreActive = this.columns.All(c => c.IsActive);
    this.allColumnsAreInactive = this.columns.All(c => !c.IsActive);
    UpdateAllColumnsAreActiveOrInactive();
  }

  void UpdateAllColumnsAreActiveOrInactive() {
    AllColumnsAreActiveOrInactive = this.columns.Any()
      && (this.allColumnsAreActive || this.allColumnsAreInactive);
  }

}

class Column : INotifyPropertyChanged {

  Boolean isActive;

  public Boolean IsActive {
    get { return this.isActive; }
    set {
      if (this.isActive == value)
        return;
      this.isActive = value;
      OnPropertyChanged("IsActive");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  protected void OnPropertyChanged(String propertyName) {
    var handler = PropertyChanged;
    if (handler != null)
      handler(this, new PropertyChangedEventArgs(propertyName));
  }

}

为了完成这个解决方案Column/Data,必须为收集重复收集方法Data/MyClass

于 2012-05-15T11:05:06.570 回答