何时使用ObservableCollection vs AdvisableCollection w / PostSharp NotifyPropertyChanged?

时间:2017-05-12 17:49:25

标签: c# containers observablecollection inotifypropertychanged postsharp

这是PostSharp support discussion(标题为:" NotifyPropertyChanged和ObservableCollection")引发了我对此主题的初步混淆。在我发布的答案中有进一步的解释(对我的回答没有100%的信心)。

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

如果是这种情况,那么我何时会使用[NotifyPropertyChanged]ObservableCollection<>?当我需要PostSharp应用的聚合模式时,是否应保留AdvisableCollection<>?或者我应该在应用PostSharp AdvisableCollection<>属性时始终使用AdvisableCollection<>

[NotifyPropertyChanged]

2 个答案:

答案 0 :(得分:1)

嗯,收到&#34; Tumbleweed&#34;关于这个问题的徽章(不是有意,但有趣......比downvotes好),我花了一些时间来解决/更好地定义我的困惑并从混乱中合并我自己的答案......

PostSharp support discussion(标题为:&#34; NotifyPropertyChanged和ObservableCollection&#34;)引发了我最初的困惑,提到了两件事:

- 4.2中添加了ObservableCollection<>中拦截更改的支持。

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

如果应用NotifyPropertyChanged属性,PostSharp的ObservableCollection<>方面似乎至少支持[AggregateAllChanges]。但是,PostSharp网站聊天功能的后续对话产生了:

- &#34;您需要使用PostSharp定义的集合类来获得NotifyPropertyChanged方面的可靠支持。见Working With Collections&#34; (提到了Aggregatable模式)。

- 阅读提供的文档后,结论似乎是我需要使用AdvisableCollection<>(PostSharp定义的集合),但是这些示例似乎都在Aggregatable模式的上下文中,亲子关系等因此我的困惑。我并没有尝试设置父子关系,只是试图在集合上获得NotifyPropertyChange

接下来是另一个support discussion,演示如何将NotifyPropertyChanged与非PostSharp定义的集合一起使用,将[AggregateAllChanges]应用于BindingList<>

- 在这种情况下,BindingList<>没有NotifyPropertyChanged预期的事件之一,因此必须使用NotifyPropertyChangedServices手动连接。

对于更多背景知识,我读到了进入聚合和合成模式的PostSharp blog post

试图将所有东西都烧掉,我的(可能是不正确的)结论是:

- [AggregateAllChanges]应用于非PostSharp定义的集合(ObservableCollection<>BindingList<>)实际上是NotifyPropertyChanged方面的选择,请注意,您应用它的集合(例如BindingList<>)可能不支持方面所需的所有事件,要求您通过NotifyPropertyChangedServices自行连接PropertyChanged通知。

- AdvisableCollection<>实现INotifyPropertyChanged以及INotifyCollectionChanged(与ObservableCollection<>一样),可用于代替标准.net集合(不是{{ 1}}虽然......不同的接口),仍然需要BindingList<>来引发PropertyChanged通知。否则,[AggregateAllChanges]的目的是允许注入与可聚合模式相关的行为。

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

答案 1 :(得分:1)

祝贺Tumbleweed徽章,并为延迟回答道歉。

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

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

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

[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<T>你是对的 - 虽然它可以使用,但它的主要目的是不同的。