WPF DataGrid вызывает BeginEdit для IEditableObject два раза? - PullRequest
16 голосов
/ 15 декабря 2010

У меня есть DataGrid, привязанный к коллекции IEditableObject.

Теперь, когда я дважды щелкну ячейку, она будет открыта для редактирования.

Забавно: BeginEdit будет вызываться два раза. Иногда для одного и того же EditableObject, но иногда для двух разных объектов (особенно когда я использую PgDn, пока не достигну конца DataGrid), сначала будет вызван правильный, затем какой-то другой элемент из коллекции, который никогда не был в фокусе .

EndEdit также вызывается дважды, но всегда для выбранного элемента, а не для неправильного.

Это известная проблема? Любые обходные пути для получения только (правильного) одного уведомления.

Ответы [ 4 ]

20 голосов
/ 03 января 2011

Если вы посмотрите на трассировку стека в отладчике при вызове BeginEdit, вы увидите, что в первый раз вызов вызывается представлением коллекции, а во второй раз - BindingGroup.

Проблема в том, что есть две вещи, которые обе считают, что они отвечают за состояние IEditableObject. Когда WPF предоставляет представление коллекции по умолчанию, он будет искать IEditableObject для объектов в коллекции и будет вызывать BeginEdit и либо EndEdit, либо CancelEdit в ответ на вызовы соответствующих методов IEditableCollectionView. Но также BindingGroup будет вызывать методы IEditableObject в ответ на вызовы BeginEdit и CommitEdit или CancelEdit.

DataGrid использует обе функции: когда вы запускаете и завершаете редактирование подряд, он уведомляет IEditableCollectionView и BindingGroup, и обе эти вещи считают, что это их ответственность по очереди. продолжить и уведомить реализацию IEditableObject об исходном объекте источника.

Так что это выглядит как ошибка в DataGrid - это вызывает два разных объекта для вызова BeginEdit (и связанных методов). И это потому, что в нем используются редактируемые виды коллекций и группы привязок - с их точки зрения, они не были предназначены для одновременного использования на одних и тех же объектах, как DataGrid их использует.

Причина, по которой вы не видите этой проблемы с сеткой в ​​Toolkit, заключается в том, что она выглядит немного более старой версией - сравнив код, который в ней показан с Reflector для .NET 4.0, вы увидите, что. NET 4.0 DataGrid имеет некоторый дополнительный код (новый метод EnsureItemBindingGroup и некоторый связанный код в MeasureOverride и OnRowValidationRulesChanged), который гарантирует, что группа привязки всегда существует, независимо от того, просите вы ее или нет. Поэтому, если WPF Toolkit будет обновлен, он, вероятно, вырастет аналогичная функция, если это не будет исправлено. (И я предполагаю, что если вы используете текущую редакцию - февраль 2010 г., когда я пишу это) - WPF Toolkit и используете свойство ItemBindingGroup, чтобы явно запросить группу привязки, вы увидите точно такую ​​же проблему. )

Это не объясняет, как вы будете получать вызовы BeginEdit для случайных объектов, как вы описали. Я не могу это воспроизвести. Но это объясняет двойные вызовы на выбранном объекте. Лучшее, что можно сделать, - это написать исходные объекты, чтобы они допускали двойные вызовы.

4 голосов
/ 19 июня 2013

Я не уверен, что бы вы использовали для прерывания события BeginEdit до того, как оно произойдет, но для EndEdit подойдет простой маркер isDirty. В вашем классе Entity, который реализует IEditableObject, добавьте следующее:

    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
3 голосов
/ 17 декабря 2010

У меня та же проблема с использованием .NET Framework 4 DataGrid.

Добавить ссылку на последнюю версию WPFToolkit

Добавить

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

и изменить <DataGrid> на <dg:DataGrid>

1 голос
/ 12 мая 2014

+ 1 @IanGriffiths для диагонализации задачи. Что касается решения (или, скорее, обходного пути), вы можете посчитать количество «ожидающих» правок. Это означает что-то вроде:

void BeginEdit()
{
    _numEdits++;
}

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

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