2009-07-20 13 views
6

Ho un controllo utente con diversi controlli figlio. Ho bisogno dell'interfaccia utente per reagire ai tasti, quindi ho deciso di inserire il codice di gestione in un evento MainControl_KeyDown. Tuttavia, quando premo un tasto nella mia applicazione, questo evento non viene attivato.Cattura eventi KeyDown in un controllo utente

Ho trovato una soluzione tramite un motore di ricerca che si basa sull'utilizzo dell'API di Windows, che vorrei evitare, in quanto sembra eccessivo per ciò che dovrebbe essere una funzione supportata correttamente dal framework .NET.

+2

ho trovato [questa risposta] [1] per essere il più utile - si sostituisce ProcessCmdKey(). [1]: http://stackoverflow.com/a/1616965/327458 – bsegraves

+0

Questo collegamento deve essere la risposta. – OfficeAddinDev

risposta

7

Si potrebbe aggiungere un gestore di eventi KeyDown per ogni controllo figlio nel controllo utente e l'evento KeyDown del controllo utente in ciascuno, in questo modo:

private void textBox1_KeyDown(object sender, KeyEventArgs e) 
{ 
    this.OnKeyDown(e); 
} 
1

forse dovresti gestire tutti gli eventi localmente e quindi attivare eventi fittizi per comunicare con il controllo principale?

o forse questo può essere un problema di messa a fuoco; se ci sono molti controlli figli e solo uno di essi è focalizzato, gli altri non reagiscono all'azione di abbassamento della chiave.

forse potresti inserire alcuni frammenti di codice qui per essere sicuro.

1

Ecco un esempio che loop di buttare ogni controllo nel modulo per allegare l'evento KeyDown. E 'come la risposta previouly in questo post, ma di gestire più casi:

using Microsoft.VisualBasic; 
using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Data; 
using System.Diagnostics; 

public class UserControlKeyboardProcessor 
{ 
    private void Control_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) 
    { 
     base.OnKeyDown(e); 
    } 

    private void UserControlKeyboardProcessor_Disposed(object sender, System.EventArgs e) 
    { 
     foreach (System.Windows.Forms.Control control in this.GetAllControls(this)) { 
      control.KeyDown -= Control_KeyDown; 
     } 
    } 

    private void UserControlKeyboardProcessor_Load(object sender, System.EventArgs e) 
    { 
     foreach (System.Windows.Forms.Control control in this.GetAllControls(this)) { 
      control.KeyDown += Control_KeyDown; 
     } 
    } 

    public Generic.List<System.Windows.Forms.Control> GetAllControls(System.Windows.Forms.Control control) 
    { 
     Generic.List<System.Windows.Forms.Control> controls = new Generic.List<System.Windows.Forms.Control>(); 

     foreach (System.Windows.Forms.Control subControl in control.Controls) { 
      controls.Add(subControl); 
      controls.AddRange(this.GetAllControls(subControl)); 
     } 

     return controls; 
    } 
    public UserControlKeyboardProcessor() 
    { 
     Load += UserControlKeyboardProcessor_Load; 
     Disposed += UserControlKeyboardProcessor_Disposed; 
    } 
} 
9

So che questa discussione è un po' vecchio, ma ho avuto un problema simile e trattati in modo diverso:
Nella principale finestra Ho modificato l'attributo KeyPreview su true. Ho registrato il gestore di eventi KeyDown della finestra principale nel mio controllo utente.

this.Parent.KeyDown += new KeyEventHandler(MyControl_KeyDown); 

Questo mi impedisce di instradare l'evento KeyDown di ogni controllo figlio sul controllo utente.
Ovviamente è importante rimuovere il gestore eventi quando si scarica il controllo utente.

Spero che questo aiuti le persone che affrontano un problema simile ora.

+0

Funziona alla grande quando un controllo viene utilizzato in più moduli e l'acquisizione di 'Enter' chiama un metodo nel modulo – Wayne

0

Ho qualche trucco.

UcBase ereditano da UesrControl

UcSub1 e UcSub2 ereditano da UcBase. UcSuperClass ereditato anche da UcBase.

UcSub1, UcSub2 utilizzano all'interno di UcSuperClass.

I pazzo UcSub1 e UcSub2 invocano ProcessCmdKey ok.

miei codici era

public class UcBase : UserControl 
{ 
    public delegate bool ProcessCmdKeyHandler(Keys keyData); 

    public ProcessCmdKeyHandler KeyHandler; 

    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     KeyHandler += ProcessKey; 

     if (Parent != null) 
     { 
      var parent = GetParentControl<UcBase>(Parent); 

      if (parent != null) 
      { 
       parent.KeyHandler += ProcessKey; 
      } 
     } 
    } 

    protected virtual bool ProcessKey(Keys keyData) 
    { 
     return false; 
    } 

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 
    { 
     const int WM_KEYDOWN = 0x100; 
     const int WM_SYSKEYDOWN = 0x104; 

     if (KeyHandler != null 
      && (msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN)) 
     { 
      if (KeyHandler(keyData) == true) 
      { 
       return true; 
      } 
     } 

     return base.ProcessCmdKey(ref msg, keyData); 
    } 

    private T GetParentControl<T>(Control control) 
     where T : Control 
    { 
     T parentControl = default(T); 
     var queue = new Queue<Control>(); 
     var targetControlType = typeof(T); 

     queue.Enqueue(control.Parent); 

     while (queue.Count > 0) 
     { 
      var parent = queue.Dequeue(); 

      if (parent != null) 
      { 
       if (parent.GetType().BaseType == targetControlType) 
       { 
        parentControl = (T)parent; 

        break; 
       } 
       else 
       { 
        queue.Enqueue(parent.Parent); 
       } 
      } 
      else 
      { 
       break; 
      } 
     } 

     return parentControl; 
    } 
} 

public class UcSub1 : UcBase 
{ 
    protected override bool ProcessKey(Keys keyData) 
    { 
     // if you process do something, and return true then UcBase.ProcessCmdKey pass by. 
     return false; 
    } 
} 

public class UcSub2 : UcBase 
{ 
    protected override bool ProcessKey(Keys keyData) 
    { 
     // if you process do something, and return true then UcBase.ProcessCmdKey pass by. 
     return false; 
    } 
} 

public class UcSuperClass : UcBase 
{ 
    private UcSub1 _ucSub1; 
    private UcSub2 _ucSub2; 

    public UcSuperClass() 
    { 
     _ucSub1 = new UcSub1(); 
     _ucSub2 = new UcSub2(); 
    } 

    protected override bool ProcessKey(Keys keyData) 
    { 
     // if you process do something, and return true then UcBase.ProcessCmdKey pass by. 
     return false; 
    } 
} 
5

È possibile aggiungere al vostro following methodusercontrol:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 
{ 
    if ((keyData == Keys.Right) || (keyData == Keys.Left) || 
     (keyData == Keys.Up) || (keyData == Keys.Down)) 
    { 
    //Do custom stuff 
    //true if key was processed by control, false otherwise 
    return true; 
    } 
    else 
    { 
    return base.ProcessCmdKey(ref msg, keyData); 
    } 
} 
Problemi correlati