Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
ObservableCollection: Inhalt austauschen
bb1898
myCSharp.de - Member



Dabei seit:
Beiträge: 110

Themenstarter:

ObservableCollection: Inhalt austauschen

beantworten | zitieren | melden

Aufgabe: Der Inhalt einer ObservableCollection soll auf Kommando komplett ausgetauscht werden (meist als Ergebnis einer Suche in einem größeren Datenbestand).

Das funktioniert, wenn die neuen Objekte der Liste einzeln zugefügt werden:

public void Refill(IEnumerable<Ship> ships)
{
	Clear();
	foreach (var ship in ships)
	{
		Add(ship);
	}
}
Eigentlich läge es doch aber nahe, die neuen Objekte in einem Rutsch zuzufügen, mit AddRange oder so. Die ObservableCollection hat allerdings keine Methode, die das tut, ich habe in der Dokumentation jedenfalls nichts dergleichen gefunden. Versucht habe ich dies hier:

public class ShipsCollection : ObservableCollection<Ship>
{
	public ShipsCollection() : base() { }

	public ShipsCollection(IEnumerable<Ship> ships) => Refill(ships);

	public void Refill(IEnumerable<Ship> ships)
	{
		Clear();
		((List)Items).AddRange(ships);
	}
}
Das wird zwar anstandslos kompiliert, das Programm startet auch und das Ergebnis der ersten Suche wird richtig angezeigt. So bald aber eine neue Suche ein anderes Ergebnis hat, gibt es eine Exception. Weil der interessante Teil des Textes dazu recht lang ist, stelle ich erst mal meine Frage und hänge ihn danach an:

Stimmt meine Vermutung, dass so ein Komplett-Austausch der Elemente einer ObservableCollection nicht möglich ist oder habe ich nur den richtigen Weg nicht gefunden?

Klar ist, dass ich eine neue Instanz der Collection mit neuem Inhalt erzeugen könnte, aber dann müsste ich INotifyPropertyChanged auf die Collection als Ganzes anwenden. Und wäre das überhaupt eine gute Idee?

Und hier der gekürzte Text zur Exception:
Fehler
System.InvalidOperationException ist aufgetreten.
HResult=0x80131509
Nachricht = Ein ItemsControl ist nicht konsistent mit seiner Elementquelle.
Weitere Informationen finden Sie in der inneren Ausnahme.
Quelle = <Die Ausnahmequelle kann nicht ausgewertet werden.>
...
Die Ausnahme wurde ausgelöst, da der Generator für Steuerelement 'System.Windows.Controls.DataGrid Items.Count:5' mit dem Namen '(unbenannt)' eine Reihe von CollectionChanged-Ereignissen empfangen hat, die nicht mit dem aktuellen Status der Elementsammlung übereinstimmen. Die folgenden Unterschiede wurden festgestellt:
Gesammelte Anzahl 1 unterscheidet sich von der tatsächlichen Anzahl 5. [Gesammelte Anzahl ist (Anzahl bei letztem Reset + #Adds - #Removes seit letztem Reset).]

Eine oder mehrere der folgenden Quellen haben möglicherweise falsche Ereignisse ausgelöst:
System.Windows.Controls.ItemContainerGenerator
System.Windows.Controls.ItemCollection
System.Windows.Data.ListCollectionView
* ShipsCrud.ShipsCollection
(Die beteiligten Quellen werden als die wahrscheinlichere Ursache des Problems betrachtet.)

Die häufigsten Ursachen umfassen (a) das Ändern der Sammlung oder deren Anzahl ohne Auslösen eines entsprechenden Ereignisses sowie (b) das Auslösen eines Ereignisses mit falschem Index- oder Elementparameter.
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1821
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@bb1898
Wenn du nur auf Standard Funktionen der ObservableCollection Collection zugreifst, dann brauchst du keine Ableitung.
Am besten wäre es, wenn du deine "ShipsCollection " nur als Container implementierst.
Dann hast du eine interne ObservableCollection vom Typ Ship und kannst dann darauf arbeiten.
Eine Ableitung von einer Kollektion wäre hier nicht sinnvoll, da du diese nicht neu implementieren willst sonstn nur die entsprechenden Methoden wiederverwendest.

T-Virus
Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 996

beantworten | zitieren | melden

Der einfachste und schnellste Weg ist das Erstellen einer neuen ObservableCollection.
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3429
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo,

wenn Du ohnehin den kompletten Inhalt austauschst, könntest Du Dir auch überlegen, die ObservableCollection selbst auszutauschen (also eine ganz neue Collection zu erzeugen).

Gruß, MarsStein

Edit:
öhmm zu spät. Aber ich poste es trotzdem, um die Ansicht von Sir Rufo zu unterstützen.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von MarsStein am .
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4001

beantworten | zitieren | melden

Hallo,

bzgl. der Exception. Dies liegt daran, daß bei der ObservableCollection<T> die virtuelle Methode InsertItem überschrieben ist:


protected override void InsertItem(int index, T item)
{
    this.CheckReentrancy();
    base.InsertItem(index, item);
    this.OnPropertyChanged("Count");
    this.OnPropertyChanged("Item[]");
    this.OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
}
Und daher führt ((List)Items).AddRange(ships) keine PropertyChanged/CollectionChanged-Ereignisse aus, welches wiederum für die Konsistenz nötig sind.
private Nachricht | Beiträge des Benutzers
bb1898
myCSharp.de - Member



Dabei seit:
Beiträge: 110

Themenstarter:

beantworten | zitieren | melden

Das ging ja fix! Danke an alle Antwortenden.
Zitat von Th69
bzgl. der Exception. Dies liegt daran, daß bei der ObservableCollection<T> die virtuelle Methode InsertItem überschrieben ist

Und daher führt ((List)Items).AddRange(ships) keine PropertyChanged/CollectionChanged-Ereignisse aus, welches wiederum für die Konsistenz nötig sind.

Danke für die Klärung! Dann habe ich also die Wahl zwischen einer Schleife mit Add-Aufrufen und einer neuen Instanz. Na schön.

@T-Virus: Ich habe die eigene Subklasse ShipsCollection nur erstellt, um an die Items-Eigenschaft heranzukommen, die ist ja protected. Aber nachdem das nicht tut, was ich mir davon erhofft habe, ist die Klasse nicht mehr nötig.
private Nachricht | Beiträge des Benutzers
lutzeslife
myCSharp.de - Member



Dabei seit:
Beiträge: 157
Herkunft: Dresden

beantworten | zitieren | melden

Oder du benutzt eine BulkObservableCollection<T> in dem du die BulkCollection<T> von Visual Studio nimmst oder du baust sie dir selbst.
Mit freundlichen Grüßen
lutzeslife
private Nachricht | Beiträge des Benutzers