Qual è il modo migliore per trovare il controllo focalizzato nell’app WinForms?

Qual è il modo preferito / più semplice per trovare il controllo che sta attualmente ricevendo l’input dell’utente (tastiera) in WinForms?

Finora ho trovato il seguente:

public static Control FindFocusedControl(Control control) { var container = control as ContainerControl; return (null != container ? FindFocusedControl(container.ActiveControl) : control); } 

Da un modulo, questo può essere chiamato semplicemente come (in .NET 3.5+ questo potrebbe anche essere definito come un metodo di estensione sul modulo) –

 var focused = FindFocusedControl(this); 

È appropriato?

Esiste invece un metodo integrato che dovrei usare?

Si noti che una singola chiamata a ActiveControl non è sufficiente quando vengono utilizzate le gerarchie. Immaginare:

 Form TableLayoutPanel FlowLayoutPanel TextBox (focused) 

(formInstance) .ActiveControl restituirà il riferimento a TableLayoutPanel, non al controllo TextBox (poiché ActiveControl sembra restituire solo figlio attivo immediato nell’albero dei controlli, mentre sto cercando il controllo foglia).

Se hai già altre chiamate all’API di Windows, non c’è nulla di male nell’usare la soluzione di Peters. Ma capisco le tue preoccupazioni al riguardo e tenderei ad una soluzione simile alla tua, usando solo le funzionalità di Framework. Dopo tutto, la differenza di prestazioni (se ce n’è una) non dovrebbe essere significativa.

Prenderò un approccio non ricorsivo:

 public static Control FindFocusedControl(Control control) { var container = control as IContainerControl; while (container != null) { control = container.ActiveControl; container = control as IContainerControl; } return control; } 

Dopo aver cercato su Internet, ho trovato quanto segue sulle FAQ di Windows Form di George Shepherd

Le librerie framework .Net non forniscono un’API per interrogare il Controllo focalizzato. Devi richiamare un’API di Windows per farlo:

[C #]

 public class MyForm : Form { [DllImport("user32.dll", CharSet=CharSet.Auto, CallingConvention=CallingConvention.Winapi)] internal static extern IntPtr GetFocus(); private Control GetFocusedControl() { Control focusedControl = null; // To get hold of the focused control: IntPtr focusedHandle = GetFocus(); if(focusedHandle != IntPtr.Zero) // Note that if the focused Control is not a .Net control, then this will return null. focusedControl = Control.FromHandle(focusedHandle); return focusedControl; } } 

ActiveControl su un modulo o contenitore restituirà il controllo attivo di tale quadro indipendentemente dalla profondità che potrebbe essere nidificata all’interno di altri contenitori.

Nel tuo esempio se il TextBox ha Focus: quindi: per Form, TableLayoutPanel e FlowLayoutPanel: la proprietà ‘ActiveControl di tutti loro sarà il TextBox!

Alcuni, ma non tutti, tipi “genuini” di ContainerControl … come Form e UserControl … espongono eventi chiave (nel caso di Form: solo se Form.KeyPreview == true possono essere utilizzati).

Altri controlli che, per impostazione predefinita, contengono altri controlli come TableLayOutPanel, GroupBox, Panel, FlowLayoutPanel, ecc. Non sono di tipo ContainerControl e non espongono KeyEvents.

Qualsiasi tentativo di trasmettere istanze di oggetti come TextBox, FlowLayoutPanel, TableLayoutPanel direttamente a ContainerControl non verrà compilato: non sono di tipo ContainerControl.

Il codice nella risposta accettata, e nella risposta successiva che corregge gli errori di ortografia della prima risposta, compila / accetta le istanze di quanto sopra come parametri perché le stai “downcasting” per digitare “Controllo facendo il tipo di parametro” Control

Ma in ogni caso il cast di ControlContainer restituirà null e l’istanza passata verrà restituita (downcast): essenzialmente un no-op.

E, sì, il codice di risposta modificato funzionerà se si passa un ControlContainer “genuino”, come un’istanza di Form, che si trova nel percorso di ereditarietà di ActiveControl, ma si sta ancora sprecando tempo a duplicare la funzione di ‘ActiveControl.

Quindi cosa sono i “veri” ContainerControls: verificali: MS docs per ContainerControl

Solo la risposta di Peter risponde davvero alla domanda esplicita, ma quella risposta ha il prezzo di usare interop, e ‘ActiveControl ti darà quello di cui hai bisogno.

Si noti inoltre che ogni controllo (contenitore o non contenitore) ha una raccolta di controlli che non è mai nullo e che molti (non li ho mai provati tutti: perché dovrei?) Il controllo di base di WinForms consente di fare “pazzi” roba “come aggiungere controlli alla ControlCollection di controlli ‘semplici’ come Button senza errori.

Ora, se il vero intento della tua domanda era quello di chiedere come trovi ContainerControl più esternoche non è sul Form stesso … di un normale controllo non contenitore Control annidato alcuni livelli arbitrari profondi … puoi usare un po ‘di le idee nella risposta: ma il codice può essere notevolmente semplificato.

Controlli regolari, ContainerControls, UserControls, ecc. (Ma non Form!) Hanno tutti una proprietà Container a cui puoi accedere per ottenere il loro contenitore immediato, ma assicurandoti di avere il ‘Container finale nel loro percorso di eredità che non è un Modulo richiede del codice per “salire” l’albero ereditario, che è dimostrato qui.

Potresti anche voler controllare la proprietà ‘HasChildren di’ Control che di solito è utile per gestire i problemi di Focus, ActiveControl e Select in WinForms. Rivedere la differenza tra Select e Focus può essere prezioso qui, e SO ha delle buone risorse su questo.

Spero che questo ti aiuti.

La soluzione di Hinek funziona bene per me, tranne che è ContainerControl , non ControlContainer. (Nel caso in cui ti stavi grattando la testa su quella linea ondulata rossa.)

  public static Control FindFocusedControl(Control control) { ContainerControl container = control as ContainerControl; while (container != null) { control = container.ActiveControl; container = control as ContainerControl; } return control; } 

Se segui ActiveControl in modo ricorsivo, non ti porta al controllo foglia che ha lo stato attivo?