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);
}