Как мне найти, какой элемент управления сфокусирован? - PullRequest
1 голос
/ 27 октября 2009

У меня есть приложение .net MDI, написанное на vb.net. Я пытаюсь запрограммировать форму, которая позволит пользователю выбрать специальный символ, такой как °, µ, ², ³, ɑ и т. Д., И вставить этот символ в любой элемент управления, на который был направлен фокус, до запуска формы через горячая клавиша или главное меню в родительском MDI.

Простой способ сделать это - выяснить, какой элемент управления был сосредоточен на какой дочерней MDI-форме, когда вызывается форма выбора символов, но я не могу найти никакой информации о том, как это сделать.

Есть идеи?

Ответы [ 4 ]

2 голосов
/ 27 октября 2009

Похоже, сообщения WM_SETFOCUS не приходят .... Мой плохой. Я почти уверен, что они прошли через метод Control.WndProc . В качестве обходного пути мне приходилось p / invoke GetFocus каждый раз, когда приходило сообщение, и сохранять дескриптор элемента управления с фокусом.

1-я секция кода - это класс фильтра, а 2-я секция кода - это тестовый код.



    public class LastFocusedControlFilter : IMessageFilter
    {
        [DllImport("user32")]
        private static extern IntPtr GetFocus();

        private IntPtr? _lastCtrl;
        private readonly Control _ctrlToIgnore;

        public LastFocusedControlFilter(Control controlToIgnore)
        {
            _ctrlToIgnore = controlToIgnore;
        }

        public bool PreFilterMessage(ref Message m)
        {
            if (!_ctrlToIgnore.IsHandleCreated || _ctrlToIgnore.Disposing || _ctrlToIgnore.IsDisposed)
            {
                return false;
            }
            IntPtr handle = GetFocus();
            if (handle != _ctrlToIgnore.Handle)
            {
                _lastCtrl = handle;
            }
            return false;
        }

        public Control GetLastFocusedControl()
        {
            return _lastCtrl.HasValue ? Control.FromHandle(_lastCtrl.Value) : null;
        }
    }
static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        using (Form form = new Form())
        {
            Action resetBackColor = null;
            for (int i = 0; i < 10; i++)
            {
                TextBox textBox = new TextBox();
                resetBackColor += delegate { textBox.BackColor = Color.White; };
                textBox.Text = ((char)('a' + i)).ToString();
                textBox.Location = new Point(0, textBox.Height * i);
                form.Controls.Add(textBox);
            }
            Button showTextButton = new Button();
            LastFocusedControlFilter msgFilter = new LastFocusedControlFilter(showTextButton);
            showTextButton.Dock = DockStyle.Bottom;
            showTextButton.Text = "Show text of last selected control";
            showTextButton.Click += delegate(object sender, EventArgs e)
             {
                 resetBackColor();
                 Control lastControl = msgFilter.GetLastFocusedControl();
                 if (lastControl == null)
                 {
                     MessageBox.Show("No control previous had focus.");
                 }
                 else
                 {
                     lastControl.BackColor = Color.Red;
                     MessageBox.Show(string.Format("Control of type {0} had focus with text '{1}'.", lastControl.GetType(), lastControl.Text));
                 }
             };
            form.Controls.Add(showTextButton);

            Application.AddMessageFilter(msgFilter);
            Application.Run(form);
        }
    }
}
1 голос
/ 27 октября 2009

Нашел более легкий путь -

[Parent Form].ActiveMdiChild.ActiveControl
1 голос
/ 27 октября 2009

Добавьте IMessageFilter и следите за сообщениями Windows, такими как WM_SETFOCUS или WM_ACTIVATE . Вы можете использовать Control.FromHandle для преобразования IntPtrs в .NET Controls.

0 голосов
/ 27 октября 2009

Вы можете добавить такой класс в ваш проект:

public class FocusWatcher
{
    private static System.Windows.Forms.Control _focusedControl;
    public static System.Windows.Forms.Control FocusedControl
    {
        get
        {
            return _focusedControl;
        }
    }

    public static void GotFocus(object sender, EventArgs e)
    {
        _focusedControl = (System.Windows.Forms.Control)sender;
    }
}

Затем для любого элемента управления в любой форме, в котором вы хотите быть кандидатом на «последний элемент управления», вы должны сделать следующее:

textBox1.GotFocus += FocusWatcher.GotFocus;

, а затем доступ к FocusWatcher.FocusedControl, чтобы получить последний элемент управления. Мониторинг сообщений будет работать, но вы должны игнорировать нежелательные сообщения (например, WM_ACTIVATE из формы Mdi).

Вы можете перебрать все элементы управления в каждой форме и добавить этот обработчик для события GotFocus, но, несомненно, есть элементы управления, для которых вы не хотите этого (например, кнопки). Вместо этого вы можете выполнить итерацию и добавить обработчик только для TextBoxes.

...