Los formularios no responden a los eventos de KeyDown

82

He estado trabajando durante un tiempo en mi proyecto de Windows Forms y decidí experimentar con los atajos de teclado. Después de leer un poco, pensé que tenía que escribir un controlador de eventos y vincularlo al evento KeyDown del formulario:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Control && e.Alt && e.KeyCode == Keys.O)
    {
        MessageBox.Show("Ctrl+Alt+O: magic!");
    }
}

Hice eso de la buena manera de abrir el panel Propiedades del diseñador de Visual Studio, luego hice doble clic en el evento KeyDown de mi formulario para generar el Form1_KeyDowncontrolador de eventos. Pero al probar mi aplicación, el formulario no responde en absoluto al atajo de teclado Ctrl+ Alt+ O. Sin embargo, el diseñador de Visual Studio generó el código para vincular el controlador de eventos al formulario:

private void InitializeComponent()
{
    // ...

    this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);

    // ...
}

Así que intenté agregar una Console.WriteLine()llamada al controlador para verificar que se estuviera llamando, pero tampoco tuve suerte.

Además, traté de establecer un punto de interrupción en la llamada de enlace de eventos (que se muestra justo arriba) y descubrí que el programa alcanza ese punto de interrupción sin problemas. Pero los puntos de interrupción que establezco dentro de la definición del método en sí nunca se alcanzan.

Para asegurarme de que estaba haciendo los primeros pasos correctamente, intenté repetirlos con:

  • Una nueva forma en la misma solución.
    Mismo problema: el formulario no responde cuando presiono mi Ctrl+AltO atajo de teclado + y el depurador ni siquiera ingresa al controlador de eventos. Intenté esto de nuevo y funciona.

  • Una nueva solución de WinForms.
    Funciona perfectamente: aparece el diálogo de mensaje (la Console.WriteLine()llamada también funciona).

Así que estoy bastante perdido aquí. ¿Qué impide que todos los formularios de este proyecto reciban eventos KeyDown?

BoltClock
fuente

Respuestas:

173

¿Su formulario tiene la propiedad KeyPreview establecida en true?

Propiedad Form.KeyPreview

Obtiene o establece un valor que indica si el formulario recibirá eventos clave antes de que el evento se pase al control que tiene el foco.

http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx

STO
fuente
19
Es un truco, disponible para mantener felices a los programadores de VB6. Tiene problemas de orden de ejecución, anula ProcessCmdKey () en su lugar.
Hans Passant
@HansPassant, no puedo encontrar nada que explique los problemas del orden de ejecución. KeyDown + KeyPreview no verá todas las claves, lo cual es un problema suficiente, pero ¿cuáles son los problemas de orden de ejecución?
kdbanman
1
Hay muchas modificaciones para detectar combinaciones de teclas de acceso directo. Ejecutado en orden, KeyPreview + KeyDown es el último muerto.
Hans Passant
54

El consejo más común para este problema en StackOverflow y MSDN 1 , 2 (incluida la respuesta aceptada aquí) es rápido y fácil:

KeyDownLos eventos se activan en a Formsiempre que su KeyPreviewpropiedad esté establecida entrue

Eso es adecuado para la mayoría de los propósitos, pero es riesgoso por dos razones:

  1. KeyDownlos controladores no ven todas las claves . Específicamente, "no puede ver el tipo de pulsaciones de teclas que se utilizan para la navegación. Como las teclas del cursor y Tab, Escape y Enter para un diálogo".

  2. Hay algunas formas diferentes de interceptar eventos clave y todas ocurren en secuencia. KeyDownse maneja en último lugar . Por lo tanto, KeyPreviewno es una gran vista previa, y el evento podría silenciarse en algunas paradas en el camino.

(Crédito a @HansPassant por esos puntos).

En su lugar, anule ProcessCmdKeysu Form:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
    if (keyData == Keys.Up)
    {
        // Handle key at form level.
        // Do not send event to focused control by returning true.
        return true;
    }
  return base.ProcessCmdKey(ref msg, keyData);
}

De esa manera, todas las claves son visibles para el método y el método es el primero en la fila para ver el evento.

Tenga en cuenta que aún tiene control sobre si los controles enfocados ven el KeyDownevento o no . Sólo volver truea bloquear la posterior KeyDownevento, en lugar de establecer KeyPressEventArgs.Handleda truecomo lo haría en un KeyDowncontrolador de eventos. Aquí hay un artículo con más detalles.

kdbanman
fuente
1
Esta es la respuesta correcta, especialmente si encuentra que PreviewKeyDown no se activará en absoluto con KeyPreview establecido en verdadero.
Tim
23

Intente establecer la KeyPreviewpropiedad en su formulario como verdadera. Esto funcionó para mí para registrar pulsaciones de teclas.

Seb Charrot
fuente