Laden...

Änderung an ObservableCollection-Items mitbekommen

Erstellt von Muck92 vor 10 Jahren Letzter Beitrag vor 10 Jahren 12.539 Views
M
Muck92 Themenstarter:in
19 Beiträge seit 2013
vor 10 Jahren
Änderung an ObservableCollection-Items mitbekommen

Hallo,

ich habe wiedermal eine Frage 😃

Und zwar habe ich eine Observable Collection die ich an ein DataGrid (hat unter anderem eine Spalte mit CheckBoxen) gebunden habe und ein Label, dass über eine gebundene Property die Anzahl der selektierten Reihen ausgeben soll. Mein Problem dabei ist, dass ich nicht weiß wie ich die Veränderung der Objekte in der Collection mitbekomme.

Ich habe irgenwie das Gefühl dass ich das schon mal gemacht habe aber ich weiß nicht mehr wie und im Internet habe ich bisher auch nichts gefunden das mir weitergeholfen hat.

T
415 Beiträge seit 2007
vor 10 Jahren

Die ObservableCollection verfügt über das Event CollectionChanged. Dieses könntest du abonieren und entsprechend darauf reagieren.

M
Muck92 Themenstarter:in
19 Beiträge seit 2013
vor 10 Jahren

Das habe ich schon versucht aber das wird nur ausgelöst, wenn ich ein Item hinzufüge/entferne und nicht wenn ich eine Property eines Ereignisses verändere.

S
248 Beiträge seit 2008
vor 10 Jahren

Wenn du Änderungen der einzelnen Objekte mitbekommen möchstes muss der Typ der Collection INotifyPropertyChanged implementieren.

Hinweis von herbivore vor 10 Jahren

Siehe dazu [Artikel] INotifyPropertyChanged implementieren

H
114 Beiträge seit 2007
vor 10 Jahren

Hallo Muck92,

die ObservableCollection selber bietet keine Möglichkeit dafür, sondern löst nur ein Event aus, wenn sich die Collection an sich ändert.
Um die Elemente innerhalb der Auflistung zu überwachen, müssten diese selber einen Event bereitstellen (z.B. via INotifyPropertyChanged) und du müsstest dieses Event für jedes einzelne Objekt registrieren (und später natürlich auch wieder deregistrieren!).
Alternativ kannst du natürlich auch eine spezialisierte Collection dafür selber implementieren und dabei z.B. auf Weak Event-Mechanismen zurückgreifen.

Grüße, HiGHteK

P
660 Beiträge seit 2008
vor 10 Jahren

Hahaha, was sagt man dazu,

ich hatte genau das selbe problem und hier ist meine Lösung:

public class ObservableCollectionExtended<T> : ObservableCollection<T> where T : INotifyPropertyChanged
	{
		public ObservableCollectionExtended(){}

		public ObservableCollectionExtended( List<T> list )
			: base( list ){}

		public ObservableCollectionExtended( IEnumerable<T> collection )
			: base( collection ){}

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

	}

MfG
ProGamer*Der Sinn Des Lebens Ist Es, Den Sinn Des Lebens Zu Finden! *"Wenn Unrecht zu Recht wird dann wird Widerstand zur Pflicht." *"Ignorance simplifies ANY problem." *"Stoppt die Piraterie der Musikindustrie"

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo ProGamer,

damit erzwingst du doch nur, dass der Elementtyp T INotifyPropertyChanged implementiert. Der Zwang ist aber nicht unbedingt nötig, an machen Stellen sogar unangebracht und er ist in gewissen Sinne auch heiße Luft, weil der Programmierer nicht gezwungen ist, ObservableCollectionExtended zu verwenden.

Wenn der Elementtyp von sich aus INotifyPropertyChanged implementiert, löst die originale ObservableCollection bei Änderungen an "ihren" Elementen von alleine die nötigen Events aus. Mit anderen Worten, es funktioniert auch mit der originalen ObservableCollection alles wie gewünscht, wenn der Elementtyp T INotifyPropertyChanged implementiert. EDIT: Bei Windows Forms scheint das nur für BindingList zu stimmen, zumindest in dem Sinne, dass die GUI-Aktualisierungen bei Änderungen an Elementen wie gewünscht klappen. Ob die BindingList die Ereignisse weiterleitet oder das Control die passenden Events abonniert, spielt für das Ergebnis letztlich keine Rolle. Alleine das Implementieren von INotifyPropertyChanged erzielt den gewünschten Effekt.

Andersherum gibt es auch immutable Objekte (Beispiel: String) bei denen keine Notwendigkeit besteht, INotifyPropertyChanged zu implementieren. Trotzdem funktionierten auch mit solchen (immutable) Typen alle Aktualisierungen des GUIs korrekt.

Deshalb ist es schon richtig und sinnvoll, dass ObservableCollection nicht erzwingt, dass der Elementtyp T INotifyPropertyChanged implementiert. Ein Zwang würde praktisch die Verwendung von immutable Objekts verhindern.

Es liegt natürlich in der Verantwortung des Implementierers des Elementtyps, nötigenfalls INotifyPropertyChanged zu implementieren.

herbivore

M
Muck92 Themenstarter:in
19 Beiträge seit 2013
vor 10 Jahren

Danke für die Antworten 😃 aber ich habs immer noch nicht 😦

Also ich habe in der Behind-Datei von meinem WPF-Window Die ObservableCollection die mit Objekten der Klasse Data gefüllt ist. Die Klasse Data implementiert INotifyPropertyChanged, genauso wie die Behind-Datei. Die Klasse Data enthält eine Property vom Typ bool und diese ist über die Collection an eine CheckBox-Spalte in einem DataGrid gebunden.

Wenn ich nun eine Checkbox aktiviere/deaktiviere wird weder der setter der Collection-Property noch das Ereignis CollectionChanged ausgelöst.

Was habe ich denn vergessen oder übersehen?

D
500 Beiträge seit 2007
vor 10 Jahren

Moin zusammen,

ich frage mich, warum die ObservableCollection<T> anstatt der BindingList<T> verwendet wird im Hinblick auf das urspruenglich beschriebene Einsatzszenario?

Wenn der Elementtyp von sich aus INotifyPropertyChanged implementiert, löst die originale ObservableCollection bei Änderungen an "ihren" Elementen von alleine die nötigen Events aus.

@herbivore: Entweder ich habe Dich falsch verstanden, allerdings loest die ObservableCollection<T> selbst meines Wissens nach keine Notifikation aus, wenn eins der enthaltenden Elemente, auch wenn es INotifyPropertyChanged impementiert, sich aendert (so auch die MSDN). Es werden lediglich Aenderungen an der Liste selbst entsprechend propagiert.

Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.

MFG,
DaMoe

Hinweis von herbivore vor 10 Jahren

Siehe dazu das EDIT im obigen Beitrag von herbivore.

742 Beiträge seit 2005
vor 10 Jahren

Ich habe mir immer Wrapper dafür geschrieben, hatte das Szenario sehr oft, da ich mal komplexere Controls für WPF geschrieben habe:


    public class ObservableCollectionWrapper<T>
    {
        private readonly ObservableCollection<T> collection;
        private readonly List<T> allItems = new List<T>();

        public ObservableCollectionWrapper(ObservableCollection<T> target)
        {
            collection = target;
            collection.CollectionChanged += collection_CollectionChanged;
        }

        private void collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                foreach (T item in allItems)
                {
                    RemoveItem(item);
                }

                allItems.Clear();
            }
            else
            {
                if (e.NewItems != null)
                {
                    foreach (T item in e.NewItems)
                    {
                        AddItem(item);

                        allItems.Add(item);
                    }
                }
                if (e.OldItems != null)
                {
                    foreach (T item in e.NewItems)
                    {
                        RemoveItem(item);

                        allItems.Remove(item);
                    }
                }
            }
        }

        private void RemoveItem(T item)
        {
            INotifyPropertyChanged propertyChanged = item as INotifyPropertyChanged;

            if (propertyChanged != null)
            {
                propertyChanged.PropertyChanged -= propertyChanged_PropertyChanged;
            }
        }

        private void AddItem(T item)
        {
            INotifyPropertyChanged propertyChanged = item as INotifyPropertyChanged;

            if (propertyChanged != null)
            {
                propertyChanged.PropertyChanged += propertyChanged_PropertyChanged;
            }
        }

        private void propertyChanged_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
        }
    }

WICHTIG: Du brauchst unbedingt eine Kopie der Liste, weil du bei einem Reset die alten Items nicht mitbekommst. Ziemlich dämlich, ist aber so.

M
Muck92 Themenstarter:in
19 Beiträge seit 2013
vor 10 Jahren

BindingList mit dem ListChanged-Ereignis klappt hervorragend 👍

Danke dafür 🙂