internal void FocusActiveControlInternal() { if (active_control != null && active_control.Visible) { // Avoid focus loops, especially with ComboBoxes, on Win98/ME. IntPtr focusHandle = XplatUI.GetFocus(); if (focusHandle == IntPtr.Zero || Control.FromChildHandle(focusHandle) != active_control) { XplatUI.SetFocus(active_control.Handle); } } else { // Determine and focus closest visible parent ContainerControl cc = this; using (_ = new Focusing()) { while (cc != null && !cc.Visible) { Control parent = cc.Parent; if (parent != null) { cc = parent.GetContainerControl() as ContainerControl; } else { break; } } } if (cc != null && cc.Visible) { XplatUI.SetFocus(cc.Handle); } } }
protected override bool ProcessDialogKey(Keys keyData) { bool tabbing = false; if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None) { Keys key = keyData & Keys.KeyCode; switch (key) { case Keys.Tab: tabbing = true; if (ProcessTabKey((keyData & Keys.Shift) == 0)) { return(true); } break; case Keys.Left: case Keys.Right: case Keys.Up: case Keys.Down: if (ProcessArrowKey(key == Keys.Right || key == Keys.Down)) { return(true); } break; } } using (_ = new Focusing(tabbing)) return(base.ProcessDialogKey(keyData)); }
protected override void Select(bool directed, bool forward) { using (_ = new Focusing()) { if (Parent != null) { IContainerControl parent = Parent.GetContainerControl(); if (parent != null) { parent.ActiveControl = this; } } if (directed && auto_select_child) { SelectNextControl(null, forward, true, true, false); } } }
internal void SetActiveControl(Control value) { using (_ = new Focusing()) { if (active_control == value && (value == null || value.Focused)) { return; } if (value != null && !Contains(value)) { throw new ArgumentException("Cannot activate invisible or disabled control."); } if (value == null) { Control previous_active_control = active_control; active_control = null; using (_ = new Focusing(false)) previous_active_control?.FireLeave(); return; } // Fire the enter and leave events if possible Form form = FindForm(); Control active = GetMostDeeplyNestedActiveControl(form == null ? this : form); Control common_ancestor = GetCommonContainer(active, value); ArrayList chain = new ArrayList(); ArrayList validation_chain = new ArrayList(); Control walk = active; // we split this up into three steps: // 1. walk up the tree (if we need to) to our root, firing leave events. // 2. validate. // 3. walk down the tree (if we need to), firing enter events. // "our root" is either the common ancestor of the current active // control and the new active control, or the current active control, // or the new active control. That is, it's either one of these three // configurations: // (1) root (2) new (3) current // / \ / \ / \ // ... ... ... ... ... ... // / \ / \ // current new current new // note (3) doesn't require any upward walking, and no leave events are generated. // (2) doesn't require any downward walking, and no enter events are generated. // as we walk up the tree, we generate a list of all controls which cause // validation. After firing the leave events, we invoke (in order starting from // the most deeply nested) their Validating event. If one sets CancelEventArgs.Cancel // to true, we ignore the control the user wanted to set ActiveControl to, and use // the Validating control instead. bool fire_enter = true; Control root = common_ancestor; active_control = value; // Generate the leave messages while (walk != common_ancestor && walk != null) { if (walk == value) { root = value; fire_enter = false; break; } using (_ = new Focusing(false)) walk.FireLeave(); /* clear our idea of the active control as we go back up */ if (walk is ContainerControl) { ((ContainerControl)walk).active_control = null; } if (walk.CausesValidation) { validation_chain.Add(walk); } walk = walk.Parent; } // Validation can be postponed due to all the controls // in the enter chain not causing validation. If we don't have any // enter chain, it means that the selected control is a child and then // we need to validate the controls anyway bool postpone_validation; Control topmost_under_root = null; // topmost under root, in the *enter* chain if (value == root) { postpone_validation = false; } else { postpone_validation = true; walk = value; while (walk != root && walk != null) { if (walk.CausesValidation) { postpone_validation = false; } topmost_under_root = walk; walk = walk.Parent; } } Control failed_validation_control = PerformValidation(form == null ? this : form, postpone_validation, validation_chain, topmost_under_root); if (failed_validation_control != null) { active_control = value = failed_validation_control; fire_enter = true; } if (fire_enter) { walk = value; while (walk != root && walk != null) { chain.Add(walk); walk = walk.Parent; } if (root != null && walk == root && !(root is ContainerControl)) { chain.Add(walk); } for (int i = chain.Count - 1; i >= 0; i--) { walk = (Control)chain [i]; using (_ = new Focusing(false)) walk.FireEnter(); } } walk = this; Control ctl = this; while (walk != null) { if (walk.Parent is ContainerControl) { ((ContainerControl)walk.Parent).active_control = ctl; ctl = walk.Parent; } walk = walk.Parent; } if (this is Form) { CheckAcceptButton(); } // Scroll control into view ScrollControlIntoView(active_control); walk = this; ctl = this; while (walk != null) { if (walk.Parent is ContainerControl) { ctl = walk.Parent; } walk = walk.Parent; } // Let the control know it's selected if (ctl.ContainsFocus && active_control != null && (!(active_control is UserControl) || (active_control is UserControl && !((UserControl)active_control).HasFocusableChild()))) { SendControlFocus(active_control); } } }