I've got a DataGrid bound to a collection of IEditableObject's.
Now when I click two times in a cell, it will be opened for editing.
Funny thing is: BeginEdit will be called two times. Sometimes for the same EditableObject, but sometimes for two different objects (especially when I use PgDn until I hit the end of the DataGrid) the correct one will be called first, then some other item from the collection, which never had been in focus before.
EndEdit is called twice, too, but always for the selected Item, not for the wrong one.
Is this a known problem? Any workarounds to get only (the right) one notification.
If you look at the stack trace in the debugger when BeginEdit
is called, you'll see that the first time, it's the collection view calling it, and the second time, it's a BindingGroup
.
The problem appears to be that there are two things that both think they are in charge of the IEditableObject
state. When WPF provides a default collection view, it will look for IEditableObject
on the objects in the collection, and will call BeginEdit
and either EndEdit
or CancelEdit
in response to calls to the corresponding IEditableCollectionView
methods. But also, the BindingGroup
will call the IEditableObject
methods in response to calls to BeginEdit
and CommitEdit
or CancelEdit
.
The DataGrid
uses both features: when you start and complete edits in a row, it notifies the IEditableCollectionView
and the BindingGroup
and both of those things think that it's their responsibility in turn to go on and notify the IEditableObject
implementation on the underlying source object.
So it looks rather like a bug in the DataGrid
- it causes two different objects to call BeginEdit
(and related methods). And it's because it makes use of editable collection views and binding groups - from the look of it, those weren't designed to be used at the same time on the same objects, in the way that the DataGrid
uses them.
The reason you don't see this problem with the grid in the Toolkit is that it appears to be a slightly older version - comparing the code in that with what Reflector shows for .NET 4.0, you'll see that the .NET 4.0 DataGrid
has some extra code (a new method, EnsureItemBindingGroup
, and some related code in MeasureOverride
and OnRowValidationRulesChanged
) that ensures that a binding group always exists, whether you ask for it or not. So if the WPF Toolkit is updated, it'll probably grow a similar feature unless this gets fixed. (And I would guess that if you use the current edition - February 2010 as I write this - of the WPF Toolkit, and you use the ItemBindingGroup
property to ask explicitly for a binding group, you'd see exactly the same problem.)
This doesn't explain how you'd get calls to BeginEdit
on random objects as you've described. I can't repro that. But it does explain double calls on the selected object. The best thing to do appears to be to code your source objects so that they will tolerate the double calls.
I'm not sure what you'd use to interrupt the BeginEdit event before it happens, but for EndEdit a simple isDirty marker will do. In your Entity class that implements IEditableObject, add the following:
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
I have same problem using .NET Framework 4 DataGrid.
Add Reference to last version of WPFToolkit
Add
xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
and change <DataGrid>
with <dg:DataGrid>
+1 @IanGriffiths for diagonsing the Problem. As for a solution (or workaround rather), you can count the number of "pending" Edits. That means something like:
void BeginEdit()
{
_numEdits++;
}
void CancelEdit()
{
if(--_numEdits < 0)
throw new Exception("WTF?");
}
void EndEdit()
{
CancelEdit();
if(_numEdits == 0)
commitEdit();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With