我有两个集合,其中一个用于Book对象,另一个用于BookViewModel对象。 当我从BookCollection中删除Book对象时,会触发CollectionChanged事件,以便BookViewModelCollection可以删除它的BookViewModel版本的书。因此继承了与事件绑定的委托函数。
BookViewModelCollection.cs
private void ModelCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
{
if (syncDisabled == false)
{
syncDisabled = true;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var book in e.NewItems.OfType<Book>().Select(v => new BookViewModel(v)))
{
this.Add(book);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (var book in e.OldItems.OfType<Book>().Select(v => new BookViewModel(v)))
{
this.Remove(book);
}
break;
case NotifyCollectionChangedAction.Reset:
this.Clear();
break;
}
syncDisabled = false;
}
}
也许从Book转换为BookViewModel会出错?正在执行代码,但Remove方法返回false,并且对象仍在集合中,尽管两个对象上的数据相同。 BookViewModel包含Book类型的对象,构造函数只执行以下操作:
BookViewModel.cs
public BookViewModel(Book b)
{
this.Book = b;
}
Book是一个设置Book的局部变量的属性。
注意:另一方面,当BookCollectionViewModel发生变化时更新BookCollection可以完全正确地使用相同的技术。
我希望有人能帮助我。如果您需要更多/其他信息,请告诉我。我也可以在Github上传文件。
祝你好运
答案 0 :(得分:3)
remove方法在MSDN上有这个文档:
如果类型T实现IEquatable泛型接口,则相等 comparer是该接口的Equals方法;否则, default equality comparer是Object.Equals。
由于您尚未实现IEquatable<T>
,因此将使用默认的相等比较器。这意味着Remove
方法将检查您要删除的项是否与集合中的某个对象具有相同的引用。显然不是这种情况,因为一个项目是一个对象而另一个项目是不同的对象:2个不同的引用。
foreach( var book in e.OldItems.OfType<Book>().Select( v => new BookViewModel( v ) ) ) {
this.Remove( book );
}
您在上面所做的是创建一堆BookViewModel
(s)然后尝试从您的集合中删除它们。但是你刚刚创建了book
,所以它之前从未存在过。
如果您希望能够这样做,那么至少应该在类型上实现IEquatable<T>
接口,以便Remove
方法可以使用它来确定您想要的项目删除是在集合中,但不仅使用引用相等,而且使用其他一些相等。
这是example(我复制了下面的代码),它通过检查2个部分是否具有相同的PartId来进行相等性检查。即使对象是不同的对象(引用)。
using System;
using System.Collections.Generic;
// Simple business object. A PartId is used to identify the type of part
// but the part name can change.
public class Part : IEquatable<Part> {
public string PartName { get; set; }
public int PartId { get; set; }
public override string ToString() {
return "ID: " + PartId + " Name: " + PartName;
}
public override bool Equals(object obj) {
if( obj == null )
return false;
Part objAsPart = obj as Part;
if( objAsPart == null )
return false;
else
return Equals( objAsPart );
}
public override int GetHashCode() {
return PartId;
}
public bool Equals(Part other) {
if( other == null )
return false;
return ( this.PartId.Equals( other.PartId ) );
}
// Should also override == and != operators.
}
作为最后一点,你可能会遇到IComparable<T>
,所以这里有不同之处:
IEquatable<T>
测试两个对象是否相等。这就是你需要的。
IComparable<T>
用于排序以指示在排序期间哪个对象位于另一个对象之前。例如,要对数字5,1进行排序,它会告诉您1在5之前进行升序排序。 IEquatable会告诉你1不等于5。
答案 1 :(得分:1)
正在执行代码,但Remove方法返回false和 尽管数据相同,但对象仍然在集合中 两个对象。
根据MSDN Remove()
方法使用默认的相等比较器。默认情况下,如果对象具有相同的值属性,则它们不相同。如果它们具有相同的引用,则两个对象相同。
我认为你正在努力解决这个问题。您的对象具有相同的属性但不具有相同的引用。
要解决此问题,您可以做两件事:实现比较器或手动删除满足条件的元素。
如果您决定实施比较器,可以按照此MSDN条款进行操作。基本上你需要实现IComparer<T>
。
如果您使用List<Book>
,则可以关注MSDN并在IEquatable<Book>
上实施Book
。
public class Book: IEquatable<Book>
{
// TODO: Implement your logic.
}
答案 2 :(得分:1)
与已经说过的内容相符。您可以在this
中找到具有相同图书价值的参考:
foreach (var book in e.OldItems.OfType<Book>())
{
BookViewModel tempBVM = this.Where(x => x.Book.name == book.name &&
c.Book.author == book.author).FirstOrDefault();
if(tempBVM != null)
{
this.Remove(tempBVM);
}
}
我只是猜测了您可能在Book类中拥有哪些属性以及您可能需要进行比较的内容。