【问题标题】:When to use ObservableCollection vs AdvisableCollection w/ PostSharp NotifyPropertyChanged?何时使用带有 PostSharp NotifyPropertyChanged 的​​ ObservableCollection 与 AdvisableCollection?
【发布时间】:2017-05-12 17:49:24
【问题描述】:

这里是 PostSharp support discussion(标题:“NotifyPropertyChanged 和 ObservableCollection”),它引发了我对这个主题的最初困惑。进一步的解释在我发布的答案中(我的答案不是 100% 有信心)。

我有点困惑 PostSharp 的 [NotifyPropertyChanged] 方面如何影响类的集合属性(如果有的话),以及我是否需要使用 ObservableCollection<>AdvisableCollection<>。如果我理解正确,如果我想要来自集合的通知,我必须至少将其更改为 ObservableCollection<>,对吗? [NotifyPropertyChanged] 方面不会神奇地使类中的任何集合类型都可观察。

如果是这样,那我什么时候使用ObservableCollection<>AdvisableCollection<>?当我需要 PostSharp 应用的聚合模式时,是否应该保留 AdvisableCollection<>?还是应该在应用 PostSharp 的 [NotifyPropertyChanged] 属性时始终使用 AdvisableCollection<>

[NotifyPropertyChanged]
public class Test {
    public int PropVal { get; set; }
    public List<string> PropCollection { get; set; } //Should this be ObservableCollection
                                                    //or AdvisableCollection?
}

【问题讨论】:

    标签: c# containers observablecollection inotifypropertychanged postsharp


    【解决方案1】:

    恭喜您获得 Tumbleweed 徽章,并为迟到的答复深表歉意。

    集合目前没有很好地与切面集成,因为现实生活中的示例需要做一些工作才能正常工作。让我解释几个关键步骤:

    [AggregateAllChanges] 指示运行时它应该将在集合上观察到的任何更改作为属性本身的更改进行中继。这尤其意味着创建了一个虚拟的 Item[] 依赖项(“标准”集合使用它来通知集合浅“状态”的变化)。

    实际上,与集合内容一起使用的属性通常在某种意义上是聚合的,不仅取决于存储在集合中的项目集,还取决于集合中各个对象的状态。目前没有办法表达和/或选择性地传递这些变化。为此,您需要创建一个派生自 ObservableCollection&lt;T&gt; 的类,如下所示:

    [NotifyPropertyChanged]
    public class ObservableCollectionEx<T> : ObservableCollection<T>
    {
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (T item in e.OldItems)
                {
                    ((INotifyPropertyChanged)item).PropertyChanged -= OnItemPropertyChanged;
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (T item in e.NewItems)
                {
                    ((INotifyPropertyChanged)item).PropertyChanged += OnItemPropertyChanged;
                }
            }
    
            base.OnCollectionChanged(e);
        }
    
        protected void OnPropertyChanged(string propertyName)
        {
            base.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
    
        protected void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyPropertyChangedServices.SignalPropertyChanged(this, "Item[]");
    
            NotifyCollectionChangedEventArgs collectionChangedEventArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
            base.OnCollectionChanged(collectionChangedEventArgs);
        }
    }
    

    上面的内容正是我们所需要的——当集合中的任何对象发生任何变化时,集合会报告它本身已经发生了变化。

    现在在一个类中它看起来像这样:

    [NotifyPropertyChanged]
    public class TestClass
    {
        [AggregateAllChanges]
        public ObservableCollectionEx<TestItem> Items { get; } = new ObservableCollectionEx<TestItem>();
    
        [SafeForDependencyAnalysis]
        public int Sum
        {
            get
            {
                if (Depends.Guard)
                {
                    Depends.On(this.Items);
                }
    
                return this.Items.Sum(x => x.Value);
            }
        }
    }
    
    [NotifyPropertyChanged]
    public class TestItem
    {
        public int Value { get; set; }
    }
    

    如果TestItem 类上的其他属性经常更改,则上述性能并不理想。在这种情况下,可以考虑向ObservableCollectionEx 添加某种过滤。

    关于AdvisableCollection&lt;T&gt;,你是对的——虽然可以使用,但主要用途不同。

    【讨论】:

    • 非常感谢您的回复,这很有帮助。不需要道歉,我只是被 Tumbleweed 徽章逗乐了,直到现在我才看到它:),无论如何,我必须深入研究这些文档和讨论,这对我很有帮助。
    【解决方案2】:

    好吧,在收到关于这个问题的“风滚草”徽章(不是故意的,但很有趣......比投反对票更好)后,我花了更多时间试图理清/更好地定义我的困惑并合并我自己的答案从混乱中...

    引发我最初困惑的 PostSharp support discussion(标题:“NotifyPropertyChanged 和 ObservableCollection”)提到了两件事:

    -在 4.2 中添加了对拦截 ObservableCollection&lt;&gt; 更改的支持。

    -要在每次集合更改时引发PropertyChanged 事件,集合必须标记为[AggregateAllChanges]

    因此,如果应用了 [AggregateAllChanges] 属性,那么 PostSharp 的 NotifyPropertyChanged 方面似乎至少支持 ObservableCollection&lt;&gt;。然而,在 PostSharp 网站的聊天功能上的后续对话产生了:

    -“您需要使用 PostSharp 定义的集合类来可靠地支持 NotifyPropertyChanged 方面。参见 Working With Collections”(其中提到了 Aggregatable 模式)。

    -阅读提供的文档后,结论似乎是我需要改用AdvisableCollection&lt;&gt;(PostSharp 定义的集合),但这些示例似乎都在 Aggregatable 模式的上下文中,与 parent-孩子的关系等等。因此我很困惑。我不是想建立父子关系,只是想在集合上获取NotifyPropertyChange

    接下来是另一个support discussion,它演示了将NotifyPropertyChanged 与非PostSharp 定义的集合一起使用,将[AggregateAllChanges] 应用于BindingList&lt;&gt;

    -在这种情况下,BindingList&lt;&gt; 没有NotifyPropertyChanged 预期的事件之一,因此必须手动连接到NotifyPropertyChangedServices

    为了了解更多背景知识,我阅读了这个PostSharp blog post,它涉及聚合和组合模式。

    试图把所有事情都归结起来,我(可能不正确)的结论是:

    -[AggregateAllChanges] 应用于非 PostSharp 定义的集合(ObservableCollection&lt;&gt;BindingList&lt;&gt;)实际上是对NotifyPropertyChanged 方面的选择加入,但需要注意的是您将其应用于的集合(例如BindingList&lt;&gt;)可能不支持方面期望的所有事件,需要您自己通过NotifyPropertyChangedServices 连接 PropertyChanged 通知。

    -AdvisableCollection&lt;&gt; 实现了INotifyPropertyChangedINotifyCollectionChangedObservableCollection&lt;&gt; 也是如此),可以用来代替标准的.net 集合(不是BindingList&lt;&gt; 虽然...不同的接口) ,并且仍然需要[AggregateAllChanges] 来引发 PropertyChanged 通知。否则,AdvisableCollection&lt;&gt; 的目的是允许注入与 Aggregatable 模式相关的行为。

    如果有人对这些假设有更正,请随时 :) 我很乐意将更清晰/更好的解释标记为答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多