Das WPF DataGrid entspricht in etwa dem Windows Form DataGridView. Mittels dieser Komponenten lassen sich einfach diverse Daten verwalten und bearbeiten. Dank DataBinding ist es auch kein großes Problem diese Daten automatisch zu laden. Unter WindowsForm ist es auch weiter kein Problem diese Daten automatisch zu speichern. Hierfür verwende ich das Event “RowValidated” des DataGrid und rufe dort ein tableAdapter.Update(dataTable) auf. Die WPF gibt es jedoch dieses Event nicht.
Das alternative Event, welches ich mir alls erstes herausgesucht habe war “RowEditEnding”. Das Problem ist hierbei jedoch, dass das Event ausgelöst wird, bevor die Daten im DataTable aktualisiert werden. Daher hat es mir nicht wirkich weitergeholfen, da die Änderungen immer erst verzögert, also nach einer weiteren Änderung gespeichert wurden.
Der Nächste Versuch war mit “SelectionChanged”. Dieses Event tritt ein, sobald eine Selektion im DataGrid geändert wurde. Mit einer kurzen Überprüfung, ob auch wirklich eine Zeile in der Selektion entfernt wurde sah dann mein Code in etwa so aus:
private void SelectionChanged(object sender, SelectionChangedEventArgs e) { if (e.RemovedItems.Count > 0) tableAdapter.Update(dataTable); }
Leider gab es auch hier wieder Probleme: Es wurden zwar Änderungen und neue Zeilen gespeichert, jedoch keine Zeilen gelöscht. Von daher war diese Lösung auch wieder für mich nicht brauchbar. Selbige Probleme gab es auch beim “SourceUpdated”-Event. Wieder haben nicht alle Ereignisse (Anlegen, Speichern, Löschen) funktioniert.
Letzendlich bin ich bei den zwei Events “RowDeleted” and “RowChanged” der DataTable hängen geblieben. Diese werden ausgeführt wenn eine Zeile hinzugefügt bzw. geändert (RowChanged) oder gelöscht wird (RowDeleted). Jedoch gab es auch hier wieder anfänglich ein paar Probleme. So wird das RowChanged Event auch logischerweise beim befüllen der DataTable ausgeführt. Das sollte es jedoch nicht. Um das zu umgehen, werden jetzt vor dem befüllen die zwei Events entfernen und nach dem füllen wieder registrieren.
dataTable.RowDeleted -= SaveChanges; dataTable.RowChanged -= SaveChanges; tableAdapter.Fill(dataTable); dataTable.RowDeleted += SaveChanges; dataTable.RowChanged += SaveChanges;
Das war dennoch nicht das Ende der Probleme. Die Methode sah bisher wie folgt aus:
if (e.Row.RowState != DataRowState.Unchanged) _tableAdapter.Update(e.Row);
Aufgrund der gesetzten Events wurden hier nach dem Update sofort wieder das Event aufgerufen und es kam zu einer System.InvalidOperationException (Fehler-Nachricht: “There is already an open DataReader associated with this Command which must be closed first.”). Die Lösung besteht hier auch wieder darin, vor dem Update die Events zu entfernen und danach neu zu registrieren.
Ich weiß nicht ob das die eleganteste und beste Lösung ist aber nach einiger rumtüftelei bin ich nun froh dass es überhaupt funktioniert. Wenn jemand einen anderen Weg weiß nur her damit.
{ 2 Kommentare } { 0 Shares }
{ 2 Kommentare… lies sie unten oder schreib selbst einen }
Hi Martin,
ich stand vor dem gleichen Problem und fand auch nichts gescheitet.
Deine Lösung ist sehr interessant, funktioniert und bringt, statt die Exceptions abzufangen, echte Performancevorteile.
Hast Du schon eine andere Lösung gefunden?
Eigentlich müsste man doch verhindern, dass das OnRowChanged/Deleted-Event noch zusätzlich pro Spalte ausgelöst wird, oder?
Gruß
Ralf
Hab bisher leider noch keine andere Lösung gefunden, bin also offen für jeden Vorschlag.