Другая стратегия заключается в использовании метода расширения для расширения Control.ControlCollection, а затем с помощью некоторого косвенного (делегата) рекурсивного синтаксического анализа коллекции Controls формы с добавлением специального обработчика «Enter», который обновляет статическую переменную. Отслеживая предыдущий активный контроль и текущий активный контроль, вы получаете то, что вам нужно ... если я полностью понимаю ваш вопрос. Вот пример, который требует FrameWork 3.5 или 4.0.
// в общедоступном статическом классе:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
private static EventHandler _event;
// extension method on Control.ControlCollection
public static void SetEnterEvent(this Control.ControlCollection theCollection, EventHandler theEvent)
{
_event = theEvent;
recurseSetEnter(theCollection);
}
// recurse all the controls and add the Enter Event :
public static void recurseSetEnter(Control.ControlCollection aCollection)
{
foreach (Control theControl in aCollection)
{
// "weed out" things like internal controls of the NumericUpDown Control
// String.IsNullOrWhiteSpace is FrameWork 4.0
// use Trim() followed by String.IsNullOrEmpty for FrameWork 3.5
if (!String.IsNullOrWhiteSpace(theControl.Name))
{
Console.WriteLine("setting enter handler for : " + theControl.Name + " : " + theControl.GetType().ToString());
theControl.Enter += _event;
}
if (theControl.Controls.Count > 0) recurseSetEnter((Control.ControlCollection)theControl.Controls);
}
}
Так, как мы используем это: в форме:
Сначала давайте определим фактический обработчик события, который будет фактически выполняться при обнаружении события Enter в любом элементе управления:
Мы будем хранить текущий активный элемент управления и предыдущий активный элемент управления в открытых статических переменных:
public static Control theActiveControl = null;
public static Control thePreviousControl = null;
А вот код, который выполняет обновление:
private void control_enter(object sender, EventArgs e)
{
thePreviousControl = theActiveControl;
theActiveControl = sender as Control;
Console.WriteLine("Active Control is now : " + theActiveControl.Name);
}
Теперь в событии Form_Load или в другом месте нам просто нужно подключить события:
// in a Form**
// define a delegate for the enter Event
private event EventHandler enter = delegate { };
// in the form load even or somewhere : assign an actual event handler to the delegate
enter += new EventHandler(control_enter);
Наконец, мы вызываем метод расширения в коллекции элементов управления формы:
this.Controls.SetEnterEvent(enter);
Обсуждение: WinForm поддерживает коллекцию ActiveControl: она будет содержать указатель на последний активированный элемент управления, независимо от того, насколько глубоко он вложен в один или несколько контейнеров: ... некоторые контейнеры (например, панели) не регистрируются как активные элементы управления в этой коллекции, даже если у них есть события Leave / Enter ... элементы управления станут ActiveControl, когда они используются / выбраны / введены / сфокусированы и т. д. К сожалению, событие ActiveControlChanged отсутствует.
[править] на практике я разрабатываю это, используя «фильтры», чтобы я мог выборочно пропустить определенные типы объектов или, например, найти какой-то «ключ» (в имени элемента управления или его теге), чтобы определить, является ли или не добавлять обработчик ... да ... это эксперимент. [Править]
[править] обратите внимание, что некоторые элементы управления, такие как PictureBox, не выставляют событие 'Enter', но этот код не вызывает ошибку: моя долгосрочная цель - найти способ проверить, не задумываясь, действительно ли конкретный элемент управления отображает данное событие перед установкой: я считаю плохой практикой просто позволять вещам, таким как PictureBox, «шевелиться». До сих пор я не нашел правильного «теста» для «контейнера» («оказалось, что ControlContainer» оказался неправильным треком). Также вы можете заметить, что панели, например, предоставляют событие «Enter», но оно запускается только тогда, когда активирован какой-либо элемент управления внутри панели. [Править]
Надеюсь, это полезно. Я уверен, что это, вероятно, можно было бы написать более элегантно, используя лямбды, но пока я «личинка», питающаяся листьями Скита в этом отношении:)