如何更新ObservableCollection类中的单个项?

xar*_*rzu 35 .net c# linq silverlight

如何更新ObservableCollection类中的单个项?

我知道怎么做Add.我知道如何在"for"循环中一次搜索ObservableCollection一个项目(使用Count作为项目的表示)但是如何查找现有项目.如果我执行"foreach"并找到需要更新的项目,如何将其重新放入ObservableCollection>

Kir*_*huk 37

您不需要删除项目,更改,然后添加.您可以使用LINQ FirstOrDefault方法使用适当的谓词查找必要的项并更改其属性,例如:

var item = list.FirstOrDefault(i => i.Name == "John");
if (item != null)
{
    item.LastName = "Smith";
}
Run Code Online (Sandbox Code Playgroud)

删除或添加项目ObservableCollection将生成CollectionChanged事件.

  • 这为我更新了集合但不更新用户界面?还有什么我应该做的吗? (2认同)
  • @jay_t55 您是说我需要用当前的物品来源替换新物品吗?一个完全相同但一个成员的单个字段改变的?乍一看似乎很浪费。特别是考虑到当我们向 GUI 添加或从中删除对象时,可观察集合能够检测并自动更新到 GUI ...... (2认同)

Tim*_* S. 35

您通常不能更改正在迭代的集合(with foreach).当然,解决这个问题的方法是在更改它时不要迭代它.(x.Id == myId并且LINQ FirstOrDefault是您的标准/搜索的占位符,重要的部分是您已获得对象的对象和/或索引)

for (int i = 0; i < theCollection.Count; i++) {
  if (theCollection[i].Id == myId)
    theCollection[i] = newObject;
}
Run Code Online (Sandbox Code Playgroud)

要么

var found = theCollection.FirstOrDefault(x=>x.Id == myId);
int i = theCollection.IndexOf(found);
theCollection[i] = newObject;
Run Code Online (Sandbox Code Playgroud)

要么

var found = theCollection.FirstOrDefault(x=>x.Id == myId);
theCollection.Remove(found);
theCollection.Add(newObject);
Run Code Online (Sandbox Code Playgroud)

要么

var found = theCollection.FirstOrDefault(x=>x.Id == myId);
found.SomeProperty = newValue;
Run Code Online (Sandbox Code Playgroud)

如果最后一个例子可以做,而你真正需要知道的是如何让事情看到你ObservableCollection知道变化,你应该INotifyPropertyChanged在对象的类上实现并确保PropertyChanged在你正在改变的属性发生变化时(理想情况下它)应该在所有公共属性上实现,如果你有接口,但功能上当然它真的只对你要更新的那些很重要).

  • 实现 INotifyPropertyChanged 为我解决了更新问题 (2认同)

Kyl*_*Mit 6

以下是Tim S的示例作为Collection类之上的扩展方法:

CS与 FirstOrDefault

public static void ReplaceItem<T>(this Collection<T> col, Func<T, bool> match, T newItem)
{
    var oldItem = col.FirstOrDefault(i => match(i));
    var oldIndex = col.IndexOf(oldItem);
    col[oldIndex] = newItem;
}
Run Code Online (Sandbox Code Playgroud)

带索引循环的CS

public static void ReplaceItem<T>(this Collection<T> col, Func<T, bool> match, T newItem)
{
    for (int i = 0; i <= col.Count - 1; i++)
    {
        if (match(col[i]))
        {
            col[i] = newItem;
            break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

想象一下,你有这个类设置

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

您可以调用以下任一函数/实现,其中match参数用于标识您要替换的项目:

var people = new Collection<Person>
{
    new Person() { Id = 1, Name = "Kyle"},
    new Person() { Id = 2, Name = "Mit"}
};

people.ReplaceItem(x => x.Id == 2, new Person() { Id = 3, Name = "New Person" });
Run Code Online (Sandbox Code Playgroud)

带索引循环的VB

<Extension()>
Public Sub ReplaceItem(Of T)(col As Collection(Of T), match As Func(Of T, Boolean), newItem As T)
    For i = 0 To col.Count - 1
        If match(col(i)) Then
            col(i) = newItem
            Exit For
        End If
    Next
End Sub  
Run Code Online (Sandbox Code Playgroud)

VB用 FirstOrDefault

<Extension()>
Public Sub ReplaceItem(Of T)(col As Collection(Of T), match As Func(Of T, Boolean), newItem As T)
    Dim oldItem = col.FirstOrDefault(Function(i) match(i))
    Dim oldIndex = col.IndexOf(oldItem)
    col(oldIndex) = newItem      
End Sub
Run Code Online (Sandbox Code Playgroud)


And*_*bel 5

这取决于它是什么类型的对象。

如果是普通的C#类,只需更改对象的属性即可。您无需对集合执行任何操作。该集合保存对对象的引用,即使对象的属性发生变化,该引用也是相同的。对象上的更改不会触发集合本身的更改通知,因为集合并没有真正更改,只是其中的对象之一发生更改。

如果它是不可变的 C# 类(例如字符串)、一种struct或另一种值类型,则必须删除旧值并添加新值。