web-dev-qa-db-fra.com

Comment mettre à jour un seul élément dans une classe ObservableCollection?

Comment mettre à jour un seul élément dans une classe ObservableCollection?

Je sais comment faire un ajout. Et je sais comment rechercher l'ObservableCollection un élément à la fois dans une boucle "pour" (en utilisant Count comme représentation de la quantité d'éléments) mais comment puis-je modifier un élément existant. Si je fais un "foreach" et trouve quel élément doit être mis à jour, comment le remettre dans la ObservableCollection>

35
xarzu

Vous n'avez pas besoin de supprimer un élément, de le modifier, puis de l'ajouter. Vous pouvez simplement utiliser la méthode LINQ FirstOrDefault pour trouver l'élément nécessaire en utilisant le prédicat approprié et modifier ses propriétés, par exemple:

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

La suppression ou l'ajout d'un élément à ObservableCollection générera un événement CollectionChanged.

37
Kirill Polishchuk

Vous ne pouvez généralement pas modifier une collection que vous parcourez (avec foreach). Le moyen de contourner cela est de ne pas le répéter lorsque vous le changez, bien sûr. (x.Id == myId et LINQ FirstOrDefault sont des espaces réservés pour vos critères/recherche, l'important est que vous ayez l'objet et/ou l'index de l'objet)

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

Ou

var found = theCollection.FirstOrDefault(x=>x.Id == myId);
int i = theCollection.IndexOf(found);
theCollection[i] = newObject;

Ou

var found = theCollection.FirstOrDefault(x=>x.Id == myId);
theCollection.Remove(found);
theCollection.Add(newObject);

Ou

var found = theCollection.FirstOrDefault(x=>x.Id == myId);
found.SomeProperty = newValue;

Si le dernier exemple réussit, et ce que vous devez vraiment savoir, c'est comment faire en sorte que votre ObservableCollection soit conscient du changement, vous devez implémenter INotifyPropertyChanged sur la classe de l'objet et être sûr de augmenter PropertyChanged lorsque la propriété que vous modifiez change (idéalement, elle devrait être implémentée sur toutes les propriétés publiques si vous avez l'interface, mais fonctionnellement bien sûr, cela n'a vraiment d'importance que pour celles que vous allez mettre à jour).

33
Tim S.

Voici exemples de Tim S comme méthodes d'extension au-dessus de la classe Collection:

CS avec 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;
}

CS avec boucle indexée

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

Usage

Imaginez que vous ayez cette configuration de classe

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Vous pouvez appeler l'une des fonctions/implémentations suivantes, comme celle-ci, où le paramètre match est utilisé pour identifier l'élément que vous souhaitez remplacer:

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

VB avec boucle indexée

<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  

VB avec 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
5
KyleMit

Cela dépend de quel type d'objet il s'agit.

S'il s'agit d'une classe C # ordinaire, modifiez simplement les propriétés de l'objet. Vous n'avez rien à faire à la collection. La collection contient une référence à l'objet qui est la même même si les propriétés de l'objet changent. Un changement sur l'objet ne déclenchera pas la notification de changement pour la collection elle-même, car la collection n'a pas vraiment changé, juste un des objets qu'elle contient.

S'il s'agit d'une classe C # immuable (telle qu'une chaîne), un struct ou un autre type de valeur, vous devez supprimer l'ancienne valeur et ajouter la nouvelle.

2
Anders Abel