WPF DataGrid calls BeginEdit on an IEditableObject two times?

后端 未结 4 793
有刺的猬
有刺的猬 2020-12-09 16:43

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: BeginE

相关标签:
4条回答
  • 2020-12-09 17:27

    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.

    0 讨论(0)
  • 2020-12-09 17:28

    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
    
    0 讨论(0)
  • 2020-12-09 17:38

    +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();
    }
    
    0 讨论(0)
  • 2020-12-09 17:46

    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>

    0 讨论(0)
提交回复
热议问题