Подтвердить что ты не робот

WPF DataGrid два раза вызывает BeginEdit в IEditableObject?

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

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

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

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

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

4b9b3361

Ответ 1

Если вы посмотрите на трассировку стека в отладчике при вызове 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, и вы используете свойство ItemBindingGroup для запроса явно для группы привязки, вы увидите точно такую ​​же проблему. )

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

Ответ 2

Я не уверен, что вы использовали бы, чтобы прервать событие 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

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

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

Добавить

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

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

Ответ 4

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

void BeginEdit()
{
    _numEdits++;
}

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

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