web-dev-qa-db-fra.com

Pourquoi ReadOnlyObservableCollection.CollectionChanged n'est-il pas public?

Pourquoi ReadOnlyObservableCollection.CollectionChanged est-il protégé et non public (comme le ObservableCollection.CollectionChanged is correspondant)?

Quelle est l'utilisation d'une collection implémentant INotifyCollectionChanged si je ne peux pas accéder à l'événement CollectionChanged?

77
Oskar

Voici la solution: Événements CollectionChanged sur ReadOnlyObservableCollection

Vous devez cast la collection vers INotifyCollectionChanged .

50
Nick

J'ai trouvé un moyen pour vous de procéder:

ObservableCollection<string> obsCollection = new ObservableCollection<string>();
INotifyCollectionChanged collection = new ReadOnlyObservableCollection<string>(obsCollection);
collection.CollectionChanged += new NotifyCollectionChangedEventHandler(collection_CollectionChanged);

Il vous suffit de faire explicitement référence à votre collection par INotifyCollectionChanged interface.

13
Restuta

Vous pouvez voter pour l’entrée de bogue sur Microsoft Connect qui décrit ce problème: https://connect.Microsoft.com/VisualStudio/feedback/details/641395/readonlyobservablecollection-t-collectionchanged-event-should-be-public

Mise à jour:

Le portail Connect a été arrêté par Microsoft. Donc, le lien ci-dessus ne fonctionne plus. 

La bibliothèque My Win Application Framework (WAF) fournit une solution: ReadOnlyObservableList class:

public class ReadOnlyObservableList<T> 
        : ReadOnlyObservableCollection<T>, IReadOnlyObservableList<T>
{
    public ReadOnlyObservableList(ObservableCollection<T> list)
        : base(list)
    {
    }

    public new event NotifyCollectionChangedEventHandler CollectionChanged
    {
        add { base.CollectionChanged += value; }
        remove { base.CollectionChanged -= value; }
    }

    public new event PropertyChangedEventHandler PropertyChanged
    {
        add { base.PropertyChanged += value; }
        remove { base.PropertyChanged -= value; }
    }
}
5
jbe

Je sais que cet article est vieux, cependant, les gens devraient prendre leur temps pour comprendre les modèles utilisés dans .NET avant de commenter. Une collection en lecture seule est un wrapper sur une collection existante qui empêche les utilisateurs de le modifier directement. Regardez ReadOnlyCollection et vous verrez qu'il s'agit d'un wrapper sur un IList<T> qui peut ou non être mutable. Les collections immuables sont une autre affaire et sont couvertes par la nouvelle bibliothèque de collections immuables

En d'autres termes, la lecture seule n'est pas la même chose que l'immuable !!!!

Ceci mis à part, ReadOnlyObservableCollection devrait implémenter implicitement INotifyCollectionChanged.

5
Jason Young

Il existe certainement de bonnes raisons de vouloir souscrire aux notifications de collecte modifiées sur un ReadOnlyObservableCollection . Ainsi, au lieu de simplement convertir votre collection sous la forme INotifyCollectionChanged , si vous vous trouvez en sous-classe ReadOnlyObservableCollection , la procédure suivante constitue un moyen plus pratique sur le plan de la syntaxe d'accéder à a CollectionChanged. événement:

    public class ReadOnlyObservableCollectionWithCollectionChangeNotifications<T> : ReadOnlyObservableCollection<T>
{
    public ReadOnlyObservableCollectionWithCollectionChangeNotifications(ObservableCollection<T> list)
        : base(list)
    {
    }

    event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged2
    {
        add { CollectionChanged += value; }
        remove { CollectionChanged -= value; }
    }
}

Cela a bien fonctionné pour moi avant.

5
porcus

C'était un succès sur Google, alors j'ai décidé d'ajouter ma solution au cas où d'autres personnes le consulteraient.

En utilisant les informations ci-dessus (sur le besoin de transtyper vers INotifyCollectionChanged ), j'ai créé deux méthodes d'extension pour enregistrer et annuler l'enregistrement. 

Ma solution - Méthodes d'extension

public static void RegisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
    collection.CollectionChanged += handler;
}

public static void UnregisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
    collection.CollectionChanged -= handler;
}

Exemple

IThing.cs

public interface IThing
{
    string Name { get; }
    ReadOnlyObservableCollection<int> Values { get; }
}

Utilisation des méthodes d'extension

public void AddThing(IThing thing)
{
    //...
    thing.Values.RegisterCollectionChanged(this.HandleThingCollectionChanged);
}

public void RemoveThing(IThing thing)
{
    //...
    thing.Values.UnregisterCollectionChanged(this.HandleThingCollectionChanged);
}

Solution OP

public void AddThing(IThing thing)
{
    //...
    INotifyCollectionChanged thingCollection = thing.Values;
    thingCollection.CollectionChanged += this.HandleThingCollectionChanged;
}

public void RemoveThing(IThing thing)
{
    //...
    INotifyCollectionChanged thingCollection = thing.Values;
    thingCollection.CollectionChanged -= this.HandleThingCollectionChanged;
}

Alternative 2

public void AddThing(IThing thing)
{
    //...
    (thing.Values as INotifyCollectionChanged).CollectionChanged += this.HandleThingCollectionChanged;
}

public void RemoveThing(IThing thing)
{
    //...
    (thing.Values as INotifyCollectionChanged).CollectionChanged -= this.HandleThingCollectionChanged;
}
0
Dan