Las cosas del NET (o cómo controlar las teclas en un DataGrid)
Esta mañana mi amigo Peni y yo hemos entablado un sesudo diálogo sobre el tema del título. La idea básica consiste en controlar todas las pulsaciones de teclas cuando un usuario trabaje dentro de un DataGrid. Lo que en un principio iba a ser una cosa sencilla se ha convertido en un buen jaleo y bastantes mensajes cruzados entre los dos.
La primera idea fue la de capturar el evento KeyPress del grid y actuar en consecuencia. Pues no funciona, o funciona sólo cuando no haya ninguna celda en él. Vale. Pues entonces controlemos el KeyPress de las celdas, pero resulta que no existe tal evento para ellas. Bien empezamos. Si un control Text lo tiene, ¿como es que un control Text dentro del grid no? Misterios del .NET Framework, de Microsoft y de sus by design, pero lo cierto es que dicho evento debería estar disponible.
Otra opción es la de comprobar si el grid tiene la posibilidad de activar un modo KeyPreview igual que tienen las fichas. Pues no, no lo tiene. Desde mi punto de vista, y seguro que desde el de Peni, es una jodida limitación bastante evidente.
Como se dijo en cierta película del siglo anterior, “siempre nos quedará París” o, lo que es lo mismo, “utilicemos el KeyPress y el KeyPreview de la ficha”, que para algo están. Asignando true a KeyPreview en una ficha, todas las pulsaciones de tecla pasan por ella antes de ser reenviadas al control correspondiente, siempre y cuando nosotros así lo queramos.
Capturamos el evento KeyPress de la ficha, evento que se disparará para todas y cada una de las teclas que se pulsen dentro de ella. En dicho evento recibimos un objeto del tipo Object llamado sender y una referencia a un objeto de la clase KeyPressEventArgs. Si asignamos true a la propiedad Handled de esta clase, la tecla se perderá para el control que estuviera destinada (otra cosa es que funcione, que no lo hace para la mayoría de los controles hijo, pasándose por el forro de donde ya sabemos la funcionalidad).
El objeto sender es el que nos interesa, pues es una instancia polimórfica del control que genera el envento, en nuestro caso, presuntamente y hasta que no se demuestre lo contrario, nuestro control grid. O eso se deja entrever en la documentación. Sólo nos queda promover dicho objeto a su clase exacta, previa comprobación de que se trata del grid y no de otro control cualquiera presente en la ficha. Para ello utilizamos un código parecido a este:
Type tipo=sender.GetType();
if(tipo.ToString()=="DataGrid") //Así no funciona, pero para efectos de demo nos vale
...
¿Qué suponemos que valdrá tipo.ToString()? Aquí es donde la presuntez pierde su valor y se convierte en certeza… ¡Vale “Form1″, que es el nombre de la ficha! Esto me lleva a preguntarme: ¿Para qué cojones sirve entonces el objeto sender? Evidentemente se trata de un absurdo más, porque ya sabemos que estamos en la ficha. En otras herramientas RAD, no voy a decir el nombre, sender vale lo que tiene que valer.
En fin, otro by design más.
Pero aquí no acaba la cosa, “aún hay más”, que diría cierto ratón volador sin alas. Vamos a por la tercera. ¿No dicen que a la tercera? Veremos. Nos queda una última técnica, la de comprobar en el evento quién tiene el foco, y si se trata del grid, lo tenemos hecho. Presuntamente hecho, porque el foco no lo tiene el grid, sino el control de edición que está dentro del grid. Para verlo deberíamos recorrer todos los subcontroles del mismo, comprobar mediante reflexión si tienen la propiedad Focused y luego consultarla. Eso o meter el código dentro de un try/catch y jugar a ver lo rápido que va… No se rían, por favor, eso de picar una tecla cada cuarto de hora es lo habitual.
Descartada esta opción, nos vamos a por la cuarta, que vamos a adelantar, funciona, es sencilla, evidente por sí misma y carente de cafeína, destrozos de teclado y gritos de frustación… Si el grid está en modo de edición, por cojones ha de tener el foco, así que, en vb, nuestra duda/problema queda, felizmente y tras casi una mañana de peleas, resuelta:
Private Sub Form1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress
If DataGridView1.IsCurrentCellInEditMode Then
MsgBox(e.KeyChar.ToString)
End If
End Sub
Gracias por leernos y no olviden mineralizarse y supervitaminarse.
