2010-12-15 5 views
16

Ich habe ein DataGrid an eine Sammlung von IEditableObject gebunden.WPF DataGrid ruft BeginEdit auf einem IEditableObject zweimal auf?

Wenn ich nun zweimal in eine Zelle klicke, wird sie zur Bearbeitung geöffnet.

Lustig ist: BeginEdit wird zweimal aufgerufen. Manchmal für dasselbe EditableObject, aber manchmal für zwei verschiedene Objekte (besonders wenn ich PgDn benutze, bis ich das Ende des DataGrids erreicht habe), wird zuerst das richtige aufgerufen, dann ein anderes Element aus der Sammlung, das vorher nie im Fokus war .

EndEdit wird auch zweimal aufgerufen, aber immer für das ausgewählte Element, nicht für das falsche.

Ist dies ein bekanntes Problem? Irgendwelche Workarounds, um nur eine Benachrichtigung zu bekommen (die richtige).

+0

Hörte interessant, so überprüfte ich mein Datagrid, die sich auch auf eine ObservableCollection gebunden ist und habe das nicht erleben ...? Meine Darstellung ist ein Objekt pro Zeile, verschmelzen Sie zufällig Objekte, die IEditableObject oder ähnliches implementieren? –

+0

Interessant. Mein Objekt implementiert nur IEditableObject und INotifyPropertyChanged, daher gibt es keine Zusammenführung. Meine ObservableCollection wird jedoch in eine benutzerdefinierte ListCollectionView eingeschlossen. Und ich habe die Spalte an eine Eigenschaft in einer Klasse in meinem IEditableObject gebunden, nicht direkt an eine Eigenschaft des IEditableObject. Zumindest habe ich jetzt einen Grund, meine Quelle zu überprüfen, danke! – Sam

+0

Die MSDN-Beispiele enthalten immer ein Flag, das BeginEdit daran hindert, seine Daten zu verarbeiten, wenn es zu einem anderen Zeitpunkt als dem ersten aufgerufen wird. Und nach meiner Erfahrung heißt es ja mehrmals. – peterG

Antwort

20

ändern Wenn Sie in dem Debugger an dem Stack-Trace aussehen, wenn BeginEdit genannt wird, werden Sie Das ist das erste Mal, dass es die Sammelansicht ist, die es aufruft, und das zweite Mal ist es ein BindingGroup.

Das Problem scheint zu sein, dass es zwei Dinge gibt, von denen beide denken, dass sie für den IEditableObject-Zustand verantwortlich sind. Wenn WPF eine standardmäßige Auflistungsansicht bereitstellt, sucht es nach IEditableObject für die Objekte in der Auflistung und ruft BeginEdit und entweder EndEdit oder CancelEdit als Reaktion auf Aufrufe der entsprechenden IEditableCollectionView-Methoden auf. Aber auch die BindingGroup ruft die IEditableObject Methoden in Reaktion auf Anrufe an BeginEdit und CommitEdit oder CancelEdit.

Die DataGrid verwendet beide Funktionen: Wenn Sie und vollständige Bearbeitungen in einer Reihe zu starten, benachrichtigt er den IEditableCollectionViewund die BindingGroup und diese beiden Dinge denken, dass es ihre Verantwortung in der Reihe zu gehen und benachrichtigen die IEditableObject Umsetzung auf das zugrunde liegende Quellobjekt.

So sieht es eher wie ein Fehler in den DataGrid - es verursacht zwei verschiedene Objekte BeginEdit (und verwandte Verfahren) zu nennen. Und das liegt daran, dass es editierbare Sammlungsansichten und Bindungsgruppen verwendet - von der Optik her waren diese nicht dafür vorgesehen, gleichzeitig auf den gleichen Objekten verwendet zu werden, so wie es die DataGrid verwendet.

Der Grund, warum Sie dieses Problem mit dem Raster im Toolkit nicht sehen, ist, dass es eine etwas ältere Version zu sein scheint - Vergleichen des Codes darin mit dem, was Reflector für .NET 4.0 zeigt, werden Sie sehen .NET 4.0 DataGrid hat zusätzlichen Code (eine neue Methode, , und einige verwandte Code in MeasureOverride und OnRowValidationRulesChanged), die sicherstellt, dass eine Bindungsgruppe immer vorhanden ist, ob Sie danach fragen oder nicht. Wenn das WPF-Toolkit aktualisiert wird, wird wahrscheinlich ein ähnliches Feature erstellt, sofern dies nicht behoben wird.(Und wenn Sie die aktuelle Ausgabe - Februar 2010, während ich dies schreibe - des WPF-Toolkits verwenden und die Eigenschaft ItemBindingGroup verwenden, um explizit nach einer verbindlichen Gruppe zu fragen, würden Sie genau das gleiche Problem sehen.)

Dies erklärt nicht, wie Sie Anrufe auf BeginEdit auf zufällige Objekte erhalten, wie Sie beschrieben haben. Das kann ich nicht wiederholen. Aber es erklärt doppelte Aufrufe für das ausgewählte Objekt. Am besten sollten Sie Ihre Quellobjekte so codieren, dass sie doppelte Aufrufe tolerieren.

3

Ich habe dasselbe Problem mit .NET Framework 4 DataGrid.

Verweis hinzufügen und letzte Version von WPFToolkit

xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit" 

hinzufügen und <DataGrid> mit <dg:DataGrid>

+0

Cool und interessant. Ist das eine andere Version, oder warum behebt das das Problem? – Sam

+1

ist anders –

4

Ich bin mir nicht sicher, was Sie verwenden würden, um das BeginEdit-Ereignis zu unterbrechen, bevor es passiert, aber für EndEdit ist ein einfacher isDirty-Marker geeignet. In Ihrer Entity-Klasse, die IEditableObject implementiert, fügen Sie folgendes:

private bool _isDirty = false; 

    #region IEditableObject Members 

    public void BeginEdit() 
    { 
     // Bug Fix: Windows Controls call EndEdit twice; Once 
     // from IEditableCollectionView, and once from BindingGroup. 
     // This makes sure it only happens once after a BeginEdit. 
     _isDirty = true; 
    } 

    public void CancelEdit() { } 

    public void EndEdit() 
    { 
     if (ItemEndEdit != null && _isDirty) 
     { 
      _isDirty = false; 
      ItemEndEdit(this); 
     } 
    } 

    #endregion 
+0

Sie sollten _isDirty = false in CancelEdit-Methode festlegen. –

0

+1 @IanGriffiths für diagonsing das Problem. Bei einer Lösung (oder eher einer Problemumgehung) können Sie die Anzahl der ausstehenden Bearbeitungen zählen. Das heißt, so etwas wie:

void BeginEdit() 
{ 
    _numEdits++; 
} 

void CancelEdit() 
{ 
    if(--_numEdits < 0) 
     throw new Exception("WTF?"); 
} 

void EndEdit() 
{ 
    CancelEdit(); 
    if(_numEdits == 0) 
     commitEdit(); 
}