Nefasto BringItemIntoView en Xceed DataGrid para WPF

Llevamos ya tiempo usando el grid de Xceed, con gran seguridad el mejor existente para WPF. Pero tiene un bug extraño: al insertar nuevas líneas en el grid (o al llamar al método BringItemIntoView para forzar que una línea sea visible), aunque haya espacio suficiente para mostrar todas las líneas, se ocultan las primeras, es decir, se hace un scroll innecesario por el que no vemos las primeras líneas, sí las últimas (siempre incluyendo la que hemos añadido o queríamos mostrar, eso sí), y debajo un gran (en ocasiones grandísimo) espacio en blanco. Esto lleva a confusión, ya que el usuario cree que las líneas se han perdido: él esta viendo que el control tiene espacio de sobra para mostrarlas y no las muestra, así que ni piensa que a la derecha hay una barra de desplazamiento que acaba de habilitarse.
Hemos encontrado este comportamiento comentado por la gente de Xceed aquí, y reconocen que se trata de un error antiguo y que pronto lo solucionarán. Nosotros estamos trabajando con la versión 3.2 y no se ha solucionado. Es una situación curiosa, ya que no parece un error difícil de solucionar, y en cambio da una mala impresión del control.
En el enlace anterior ofrecen una solución al problema de pulsar Ctrl-Fin, que provoca una situación similar, y nosotros hemos adaptado esa solución para evitar el problema en general, escuchando el evento Scroll del ScrollViewer del control. Para escuchar el evento, basta con localizar el ScrollViewer por su nombre interno en la plantilla del control DataGridControl:

var scroll = (ScrollViewer)grid.Template.FindName("PART_ScrollViewer", grid);
scroll.ScrollChanged += DataGridScrollChanged;

En la gestión del evento, nos aseguramos de que no estemos mostrando zonas muertas innecesarias al final del control, suponiendo un alto genérico para los elementos, en mi caso 25. Esto debería poder hacerse con ViewportHeight, como indico en el comentario, pero ahí parece residir el problema de todo: cuando en el control caben unos 20 elementos, ViewportHeight devuelve 5.0 indicando que sólo caben 5, de ahí el scroll innecesario, y de ahí que no podamos confiar en su valor y debamos estimarlo.

private static void DataGridScrollChanged(object sender, ScrollChangedEventArgs e) {
var sv = (ScrollViewer)sender;
double capacidad = sv.ActualHeight / 25;    //Esto debería devolverlo ViewportHeight
double maxOffset = sv.ExtentHeight - capacidad;
if(sv.VerticalOffset > maxOffset)
sv.ScrollToVerticalOffset(maxOffset);
}

Aunque la estimación de 25 de altura para cada item puede ser muy cercana a la realidad, en el caso de que no lo sea los resultados seguirán siendo satisfactorios: el scroll automático tendrá lugar antes de llegar al final del control, y se dejará una pequeña zona muerta (como en el problema original). Pero esta pequeña zona muerta no lleva a confusión al usuario, que la entiende, puesto que hay filas casi hasta el final del control; la confusión se produce cuando sólo está relleno un cuarto de la superficie del control y se ocultan filas por el scroll.

Edito 14:22: Faltaba navegar por Template para que la búsqueda de PART_ScrollViewer funcionara.

Anuncios
Esta entrada fue publicada en WPF y etiquetada , , , . Guarda el enlace permanente.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s