WPF DataGrid llama a BeginEdit en un objeto IEditableObject dos veces.
(4)
+1 @IanGriffiths para diagnosticar el problema. En cuanto a una solución (o una solución alternativa), puede contar el número de ediciones "pendientes". Eso significa algo como:
void BeginEdit()
{
_numEdits++;
}
void CancelEdit()
{
if(--_numEdits < 0)
throw new Exception("WTF?");
}
void EndEdit()
{
CancelEdit();
if(_numEdits == 0)
commitEdit();
}
Tengo un DataGrid enlazado a una colección de IEditableObject''s.
Ahora, cuando hago clic dos veces en una celda, se abrirá para su edición.
Lo curioso es que: BeginEdit se llamará dos veces. A veces para el mismo EditableObject, pero a veces para dos objetos diferentes (especialmente cuando uso PgDn hasta que llego al final del DataGrid) se llamará primero al correcto, luego a algún otro elemento de la colección, que nunca había estado enfocado antes .
EndEdit también se llama dos veces, pero siempre para el elemento seleccionado, no para el incorrecto.
¿Es este un problema conocido? Cualquier solución para obtener solo (el derecho) una notificación.
No estoy seguro de lo que usarías para interrumpir el evento BeginEdit antes de que suceda, pero para EndEdit, un simple marcador de IsDirty servirá. En su clase de entidad que implementa IEditableObject, agregue lo siguiente:
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
Tengo el mismo problema al usar .NET Framework 4 DataGrid.
Añadir referencia a la última versión de WPFToolkit
Añadir
xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
y cambie <DataGrid>
con <dg:DataGrid>
Si observa el seguimiento de la pila en el depurador cuando se llama a BeginEdit
, verá que la primera vez, es la vista de colección que lo llama, y la segunda vez, es un BindingGroup
.
El problema parece ser que hay dos cosas que ambos piensan que están a cargo del estado IEditableObject
. Cuando WPF proporciona una vista de colección predeterminada, buscará IEditableObject
en los objetos de la colección, y llamará BeginEdit
y EndEdit
o CancelEdit
en respuesta a las llamadas a los métodos correspondientes de IEditableCollectionView
. Pero también, BindingGroup
llamará a los métodos IEditableObject
en respuesta a las llamadas a BeginEdit
y CommitEdit
o CancelEdit
.
El DataGrid
usa ambas funciones: cuando inicia y completa las ediciones seguidas, notifica a IEditableCollectionView
y BindingGroup
y ambas cosas piensan que es su responsabilidad continuar y notificar la implementación de IEditableObject
en el objeto de origen subyacente.
Así que parece un error en el DataGrid
: hace que dos objetos diferentes llamen BeginEdit
(y métodos relacionados). Y es porque utiliza vistas de colección editables y grupos de enlace; por su aspecto, no fueron diseñados para usarse al mismo tiempo en los mismos objetos, de la forma en que DataGrid
usa.
La razón por la que no ve este problema con la cuadrícula en el Kit de herramientas es que parece ser una versión un poco más antigua; comparando el código con lo que Reflector muestra para .NET 4.0, verá que .NET 4.0 DataGrid
tiene algún código adicional (un nuevo método, EnsureItemBindingGroup
, y algún código relacionado en MeasureOverride
y OnRowValidationRulesChanged
) que garantiza que siempre exista un grupo de enlace, ya sea que lo solicite o no. Por lo tanto, si el Kit de herramientas de WPF se actualiza, probablemente crecerá una característica similar a menos que esto se solucione. (Y supongo que si usa la edición actual, febrero de 2010, mientras escribo esto, del Kit de herramientas de WPF, y usa la propiedad ItemBindingGroup
para solicitar explícitamente un grupo de enlace, verá exactamente el mismo problema).
Esto no explica cómo recibirías llamadas a BeginEdit
en objetos aleatorios como lo has descrito. No puedo reprochar eso. Pero sí explica las llamadas dobles en el objeto seleccionado. Lo mejor que se puede hacer es codificar los objetos de origen para que toleren las llamadas dobles.