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.