web-dev-qa-db-fra.com

RemoveAll for ObservableCollections?

Je suis à la recherche d'une méthode Linq (telle que la méthode RemoveAll pour List) permettant de supprimer les éléments sélectionnés de mon ObservableCollection.

Je suis trop nouveau pour créer une méthode d'extension pour moi-même. Existe-t-il un moyen de supprimer des éléments d'ObservableCollection en passant une expression Lambda?

58
Arpit Khandelwal

Je ne suis pas au courant d'un moyen de supprimer uniquement les éléments sélectionnés. Mais créer une méthode d'extension est simple: 

public static class ExtensionMethods
{
    public static int Remove<T>(
        this ObservableCollection<T> coll, Func<T, bool> condition)
    {
        var itemsToRemove = coll.Where(condition).ToList();

        foreach (var itemToRemove in itemsToRemove)
        {
            coll.Remove(itemToRemove);
        }

        return itemsToRemove.Count;
    }
}

Cela supprime tous les éléments de la ObservableCollection qui correspondent à la condition. Vous pouvez l'appeler comme ça: 

var c = new ObservableCollection<SelectableItem>();
c.Remove(x => x.IsSelected);
84
Daniel Hilgarth

Itérer à l'envers devrait être plus efficace que créer une collection temporaire comme dans l'exemple de Daniel Hilgarth.

public static class ObservableCollectionExtensions
{
    public static void RemoveAll<T>(this ObservableCollection<T> collection,
                                                       Func<T, bool> condition)
    {
        for (int i = collection.Count - 1; i >= 0; i--)
        {
            if (condition(collection[i]))
            {
                collection.RemoveAt(i);
            }
        }
    }
}
37
guams

Que diriez-vous de cette mise en œuvre pour un one-liner?

observableCollection.Where(l => l.type == invalid).ToList().All(i => observableCollection.Remove(i))

-- Modifier --

Désolé, oui, vous avez besoin d'une liste de tâches () au milieu pour forcer l'évaluation de la première moitié, car LINQ effectue l'évaluation paresseuse par défaut.

13
simonalexander2005

Chacune des solutions proposées ici qui utilise la routine pour supprimer un élément un par un a une faute. Imaginez que vous ayez beaucoup d’articles dans une collection observable, disons 10 000 articles. Ensuite, vous souhaitez supprimer les éléments qui remplissent certaines conditions. 

Si vous utilisez la solution de Daniel Hilgarth et appelez: c.Remove(x => x.IsSelected); et que, par exemple, 3000 éléments doivent être supprimés, la solution proposée vous informera de chaque suppression d'élément. Cela est dû au fait que l'implémentation interne de Remove(item) informe de ce changement. Et cela sera appelé pour chacun des 3000 articles en cours de suppression.

Donc, au lieu de cela, j'ai créé un descendant de ObservableCollection et ajouté une nouvelle méthode RemoveAll(predicate)

[Serializable]
public class ObservableCollectionExt<T> : ObservableCollection<T>
{
    public void RemoveAll(Predicate<T> predicate)
    {
        CheckReentrancy();

        List<T> itemsToRemove = Items.Where(x => predicate(x)).ToList();
        itemsToRemove.ForEach(item => Items.Remove(item));

        OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

La ligne intéressante est itemsToRemove.ForEach(item => Items.Remove(item));. L'appel direct à Items.Remove(item) ne vous informera pas de l'élément supprimé.

Après la suppression des éléments requis, les modifications sont immédiatement notifiées par des appels:

OnPropertyChanged(new PropertyChangedEventArgs("Count"));
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
9
psulek

Voici ma version d'une solution de méthode d'extension, qui n'est qu'une légère variation de la réponse acceptée, mais présente l'avantage que le compte renvoyé est basé sur confirmé suppression de l'élément de la collection:

public static class ObservableCollectionExtensionMethods
{
    /// <summary>
    /// Extends ObservableCollection adding a RemoveAll method to remove elements based on a boolean condition function
    /// </summary>
    /// <typeparam name="T">The type contained by the collection</typeparam>
    /// <param name="observableCollection">The ObservableCollection</param>
    /// <param name="condition">A function that evaluates to true for elements that should be removed</param>
    /// <returns>The number of elements removed</returns>
    public static int RemoveAll<T>(this ObservableCollection<T> observableCollection, Func<T, bool> condition)
    {
        // Find all elements satisfying the condition, i.e. that will be removed
        var toRemove = observableCollection
            .Where(condition)
            .ToList();

        // Remove the elements from the original collection, using the Count method to iterate through the list, 
        // incrementing the count whenever there's a successful removal
        return toRemove.Count(observableCollection.Remove);
    }
}
0
Chris Peacock
ObservableCollection<AppVariable<G>> _appVariables = new new ObservableCollection<AppVariable<G>>();

var temp = AppRepository.AppVariables.Where(i => i.IsChecked == true).OrderByDescending(k=>k.Index);

foreach (var i in temp)
{
     AppRepository.AppVariables.RemoveAt(i.Index);
}
0
user10860989

Il n’existe aucun moyen de transmettre une expression à ObservableCollection pour supprimer les éléments correspondants, de la même manière qu’une liste générique. ObservableCollection ajoute et supprime un élément à la fois.

Pour ce faire, vous devrez créer votre propre implémentation de INotifyCollectionChanged ou créer une méthode d'extension au fur et à mesure que vous mentionnez.

0
jjrdk