【问题标题】:Is there a way to get notified when a property changes groups in a sorted collection?当属性更改排序集合中的组时,有没有办法得到通知?
【发布时间】:2011-11-12 18:54:20
【问题描述】:

更具体地说,假设我们有一个按属性 P1 和 P2 排序的集合,如下所示:

  • 一个1
  • A 2
  • A 2
  • 一个3
  • B 1
  • B 1
  • B 2
  • B 3

通过集合执行 foreach 时,我希望在属性更改时得到通知。
因此,对于 P1,我需要按特定顺序发送以下 4 个通知:

  1. OnBeforeGroup(P1, "A")
  2. OnAfterGroup(P1, "A")
  3. OnBeforeGroup(P1, "B")
  4. OnAfterGroup(P1, "B")

对于 P2,这将发出 12 个通知,请给我列表。

当然,我可以在每个用例中执行此操作,方法是在 foreach 循环 (OldP1 = P1) 中保存“旧”属性值并在 P1 != OldP1 时触发事件/执行方法,但这是不可重用的。

是否有一个集合已经实现了这种模式?
如果没有,有什么建议可以让它更可重用吗?

编辑:注意,如果某些属性值与之前迭代中的不同,我只想在 foreach 循环期间得到通知,这与 INotifyPropertyChanged 等无关。

【问题讨论】:

    标签: c# sorting collections notifications grouping


    【解决方案1】:

    .NET 有ObservableCollection<T>,但它用于观察存储对象和集合本身发生的变化。您的集合没有改变(假设我理解正确) - 如果某些属性值与之前的迭代不同,您只想在循环期间得到通知。

    就可重用代码而言,可能会为您指明正确的方向:

    public class PropertyWatcher<TSource>
    {
        // initialization code omitted
        private Dictionary<string, object> previousValues;
        private Dictionary<string, Func<TSource, object>> selectors; 
    
        public void RegisterWatcher<TSource>(Func<TSource, object> propertySelector, 
            string propertyName)
        {
            this.selectors.Add(propertyName, propertySelector);
            this.previousValues.Add(propertyName, null);
        }
    
        public void NotifyIfDifferent<TObject, TPropertyType>(TSource currentItem)
        {
            foreach (var key in this.selectors.Keys)
            {
                var selector = this.selectors[key];
                var currentValue = selector(currentItem);
                if (!currentValue.Equals(this.previousValues[key]))
                {
                    // raise notification, event; antyhing to your liking
                }
    
                this.previousValues[key] = currentValue;
            }
        }
    }
    

    并且,假设我们正在处理您提到的 P1 和 P2 属性,用法如下所示:

    var list = new List<SomeObject>(); // list of items you intend to watch
    var watcher = new PropertyWatcher<SomeObject>();
    watcher.RegisterWatcher((SomeObject o) => o.P1, "P1");
    watcher.RegisterWatcher((SomeObject o) => o.P2, "P2");
    foreach (var item in list)
    {
        watcher.NotifyIfDifferent(item);
    }
    

    这绝不是完整的解决方案。它应该在涉及简单值时起作用(因此.Equals 可以轻松处理比较)。当然,您仍然需要向 PropertyWatcher 类添加一些事件,并且可能会在这里和那里调整它 - 但我认为总体思路相当容易掌握。

    不过,对于更高级的场景,我想您必须采用更通用的方法。

    【讨论】:

      【解决方案2】:

      不确定 C# 是否有方面,但这可能是一个地方。否则,您可以向您的类添加一个更改委托,然后在您的属性方法的 set 部分中,您可以调用该委托:

      private delegate void beforeGroup( MyObject current, MyObject changesTo );
      private delegate void afterGroup( MyObject current, MyObject changedFrom );
      
      public MyObject P1 {
          get {
              return p1;
          }
          set {
              beforeGroup( p1, value );
              MyObject oldValue = p1;
              p1 = value;
              afterGroup( p1, oldValue );
          }
      }
      

      【讨论】:

      • 这不适合我的用例。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-21
      • 1970-01-01
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多