C# 使用INotifyPropertyChanged代替ObservableCollection

C# 使用INotifyPropertyChanged代替ObservableCollection,c#,wpf,observablecollection,inotifypropertychanged,C#,Wpf,Observablecollection,Inotifypropertychanged,我将列表视图绑定到一个集合,我希望列表视图在向集合中添加项目时自动更新。我设法使用ObservableCollection使其工作,但我宁愿使用INotifyPropertyChanged。也许你能给我一个暗示我做错了什么 首先,这里是XAML的(相关部分): 以下是相关课程: public class Family : INotifyPropertyChanged { public string LastName { get; private set; } private

我将
列表视图
绑定到一个集合,我希望
列表视图
在向集合中添加项目时自动更新。我设法使用
ObservableCollection
使其工作,但我宁愿使用
INotifyPropertyChanged
。也许你能给我一个暗示我做错了什么

首先,这里是XAML的(相关部分):


以下是相关课程:

public class Family : INotifyPropertyChanged
{
    public string LastName { get; private set; }

    private readonly IList<Member> _members;
    public IEnumerable<Member> Members { get => _members; }

    public Family(string lastName, IEnumerable<Member> members)
    {
        LastName = lastName;
        _members = members.ToList();
    }

    public void AddMember(string name)
    {
        var member = new Member { FirstName = name };
        _members.Add(member);
        OnPropertyChanged(nameof(Members));
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

public class Member
{
    public string FirstName { get; set; }
}
公共类族:INotifyPropertyChanged
{
公共字符串LastName{get;private set;}
私人只读IList_成员;
公共IEnumerable成员{get=>\u Members;}
公共族(字符串lastName,IEnumerable成员)
{
LastName=LastName;
_members=members.ToList();
}
public void AddMember(字符串名称)
{
var成员=新成员{FirstName=name};
_成员。添加(成员);
OnProperty变更(成员名称);
}
公共事件属性更改事件处理程序属性更改;
受保护的void OnPropertyChanged([CallerMemberName]字符串名称=null)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称));
}
}
公共班级成员
{
公共字符串名{get;set;}
}

如果我使用此代码并在某处调用
AddMember
,它将不会更新ListView GUI。我不明白为什么不能,因为
AddMember
调用
OnPropertyChanged(nameof(Members))
,而
Members
列表视图的绑定对象。因此,它应该得到有关更改的通知

那么我做错了什么?


如果我将
IList\u members
更改为
observedcollection\u members
并将
\u members=members.ToList()
更改为
\u members=new observedcollection(members)
,它将按预期工作。

\u members
集合中添加一项后,
成员返回的引用仍然是相同的。收集的
Equals
方法通常会比较引用,而不是项目。因此,绑定不会检测到更改,也不会重新评估属性


如果要使其正常工作,可以执行以下操作之一:

  • Assign
    null
    临时、raise属性更改、重新分配集合并再次更改raise属性,因此绑定检测到更改的引用(感谢@Ash)

  • 简单的方法是,在添加成员时重新创建集合,例如:

    public void AddMember(string name)
    {
       var member = new Member { FirstName = name };
       _members = _members.ToList();
       _members.Add(member);
       OnPropertyChanged(nameof(Members));
    }
    
    这是昂贵的,因为有很多不必要的分配,不要这样做


如您所见,这两种方法都有其缺点,要么触发额外的属性更改通知,要么进行不必要的分配,这将额外导致
列表视图每次删除并重新创建其所有项目。这就是为什么有一个实现的
ObservableCollection
类型,它允许专门通知添加和删除的项以及其他操作。

首先,您可以确定族不是ObservableCollection。毕竟,你可以用可观察的集合做很多在家庭中做不到的事情。例如:替换(成员)在家庭中意味着什么

问题是,您忘了实现。 使用此界面,您可以通知其他人您添加了元素(以及移动、删除等)

因为如果图元被移动/删除/等等,您还必须通知。如果您的家人能够做的不仅仅是添加,那么这将花费一些开发工作

因此,改变你的想法可能是个好主意
私有只读IList成员
进入一个
可观测集合
,并通过该可观测集合实现接口

class Family : INotifyPropertyChanged, INotifyCollectionChanged
{
    public string LastName { get; private set; }

private readonly ObservableCollection<Member> members;

public IEnumerable<Member> Members => this.members;

public event NotifyCollectionChangedEventHandler CollectionChanged
{
    add => this.members.NotifyCollectionChangedEventHandler.CollectinChanged += value;
    remove => this.members.NotifyCollectionChangedEventHandler.CollectinChanged -= value;
}
不确定是否需要方法来移动和替换族成员,但即使需要,它们也将是对相应ObservableCollection方法的一行调用


您已经完全隐藏了您正在使用的是一个
ObservableCollection
,因此,如果将来您需要完全摆脱ObservableCollection,您的用户将不必更改,只要您承诺实现接口。

“它应该得到有关更改的通知”-它得到通知,然后比较当前值和以前的值,发现它们相等,并且不执行任何操作。您可以在类中实现INotifyCollectionChanged。只能在添加一个项目后重建所有项目costly@ASh你能给我指一些链接来解释你暗示了什么(或者解释你自己)?关于这种比较:什么是比较,什么时候比较?为什么以前的值和当前值相等?(确保它们在引用方面相同,但内容已更改。)重建所有项目是什么意思?在通知
成员
属性后,将比较ItemsSource的当前值和成员的新值。它们是对_成员列表的相同引用。集合内容无关紧要当您分配新项目资源时,ListView将删除所有项目,然后为新集合的元素创建新项目(重构),当您使用ObserviceCollection说“它按预期工作”时,为什么不坚持使用标准方法呢?这是你通常会做的。其他任何事情看起来都很尴尬。“如果你想让它发挥作用,你每次都需要重新创建这个集合”——一点也不。只需将属性重置为null,引发通知,将同一集合重新分配给属性,然后再次引发通知。没有内存分配needed@ASh非常感谢,我没有想到这一点。有一个输入错误,链接是正确的,但不是名称,当然是“INotifyCollectionChanged”。
public void AddMember(string name)
{
   var member = new Member { FirstName = name };
   _members = _members.ToList();
   _members.Add(member);
   OnPropertyChanged(nameof(Members));
}
public class Family : INotifyPropertyChanged, INotifyCollectionChanged
{
    ...
class Family : INotifyPropertyChanged, INotifyCollectionChanged
{
    public string LastName { get; private set; }

private readonly ObservableCollection<Member> members;

public IEnumerable<Member> Members => this.members;

public event NotifyCollectionChangedEventHandler CollectionChanged
{
    add => this.members.NotifyCollectionChangedEventHandler.CollectinChanged += value;
    remove => this.members.NotifyCollectionChangedEventHandler.CollectinChanged -= value;
}
public void Add(Member member)
{
    this.members.Add(member);
}

public void Remove(Member member)
{
    this.members.Remove(member);
}