Как захватить события mousemove под дочерними элементами управления - PullRequest
5 голосов
/ 12 ноября 2009

Я пытаюсь обработать событие щелчка мышью в определенной форме, которое должно срабатывать, если курсор мыши находится между набором координат - скажем, квадрат.

Я понимаю, что если бы у меня была пустая форма, я мог бы просто присоединиться к событию перемещения мыши, и я ушел. Но в действительности может быть до 10 различных перекрывающихся элементов управления, и в моем тестовом приложении событие mousemove срабатывает, только если курсор находится на самой форме, а не над дочерним элементом управления.

Кто-нибудь знает, как обрабатывать это событие, когда во время разработки существует неизвестное количество дочерних элементов управления?

Есть ли простой однострочник, который я могу использовать?

Ответы [ 5 ]

7 голосов
/ 21 августа 2012

Я знаю, что этот пост довольно старый, но мне кажется, что самым простым способом было бы реализовать форму IMessageFilter. В конструкторе (или в OnHandleCreated) вы вызываете

Application.AddMessageFilter(this);

и тогда вы можете перехватить сообщения всех окон в вашей реализации IMessageFilter.PreFilterMessage.

Вероятно, вам понадобится P / Invoke для метода WIN32 IsChild

[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);

вместе со свойством Handle формы для обеспечения обработки правильных сообщений.

7 голосов
/ 12 ноября 2009

попробуйте это:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        AddMouseMoveHandler(this);
    }

    private void AddMouseMoveHandler(Control c)
    {
        c.MouseMove += MouseMoveHandler;
        if(c.Controls.Count>0)
        {
            foreach (Control ct in c.Controls)
                AddMouseMoveHandler(ct);
        }
    }

    private void MouseMoveHandler(object sender, MouseEventArgs e)
    {
        lblXY.Text = string.Format("X: {0}, Y:{1}", e.X, e.Y);
    }
}
0 голосов
/ 03 июля 2012

Я знаю, что немного опоздал на удар, но у меня были проблемы с этим ранее сегодня, когда я использовал Панель в качестве строки заголовка. У меня была метка для отображения некоторого текста, графическое окно и несколько кнопок, все они были вложены в Panel, но мне нужно было перехватывать событие MouseMove независимо от того.

Что я решил сделать, так это реализовать обработчик рекурсивных методов, поскольку у меня был только 1 уровень вложенных элементов управления, это может не очень хорошо масштабироваться, когда вы начинаете приближаться к смешным уровням вложенности.

Вот как я это сделал:

    protected virtual void NestedControl_Mousemove(object sender, MouseEventArgs e)
    {
        Control current = sender as Control;
        //you will need to edit this to identify the true parent of your top-level control. As I was writing a custom UserControl, "this" was my title-bar's parent.
        if (current.Parent != this) 
        {
            // Reconstruct the args to get a correct X/Y value.
            // you can ignore this if you never need to get e.X/e.Y accurately.
            MouseEventArgs newArgs = new MouseEventArgs
            (
                e.Button, 
                e.Clicks, 
                e.X + current.Location.X, 
                e.Y + current.Location.Y, 
                e.Delta
            );
            NestedControl_Mousemove(current.Parent, newArgs);
        }
        else
        {
            // My "true" MouseMove handler, called at last.
            TitlebarMouseMove(current, e);
        }
    }

    //helper method to basically just ensure all the child controls subscribe to the NestedControl_MouseMove event.
    protected virtual void AddNestedMouseHandler(Control root, MouseEventHandler nestedHandler)
    {
        root.MouseMove += new MouseEventHandler(nestedHandler);
        if (root.Controls.Count > 0)
            foreach (Control c in root.Controls)
                AddNestedMouseHandler(c, nestedHandler);
    }

А затем настроить его относительно просто:

Определите ваш "истинный" обработчик:

    protected virtual void TitlebarMouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            this.Text = string.Format("({0}, {1})", e.X, e.Y);
        }
    }

А затем настроить элементы управления подписчиками событий:

//pnlDisplay is my title bar panel.
AddNestedMouseHandler(pnlDisplay, NestedControl_Mousemove);

Относительно прост в использовании, и я могу ручаться за то, что он работает:)

0 голосов
/ 12 ноября 2009

imho, здесь есть некоторая бинарная ситуация: нет "одной строки". Единственное решение, которое я вижу, - это поместить ваши элементы управления, которые не реализуют события, в контейнер .NET, который это делает.

Когда любой элемент управления получает щелчок, обычно ожидается, что он станет активным элементом управления формы (к которому всегда может обращаться this.ActivceControl).

Но, в частности, если элемент управления, по которому вы щелкнули, захватывает мышь, что-то должно вызывать событие, поскольку .NET не реализует «всплывающее» событие (как в WPF).

Обычный способ справиться с расширением поведения любого объекта, который запечатан, или что-то еще, это написать метод расширения, и я нашел, что написание расширений для Control довольно просто, но я не знаю, поможет ли это вам в этом дело. К сожалению, я сейчас нахожусь за пределами своей страны, и у меня нет Visual Studio, с которой можно поиграться.

Одна из стратегий, которую вы можете использовать, чтобы определить, попадает ли данная точка формы в пределы какого-либо элемента управления, состоит в перечислении областей (границ) всех элементов управления в форме через 'Formal of Forms Control.Collection (this. Элементы управления). Но если у вас есть перекрывающиеся элементы управления, у вас возникнет проблема с несколькими элементами управления, возможно, содержащими данную точку.

лучший, Билл

0 голосов
/ 12 ноября 2009

Почему бы вам просто не использовать обработчики событий управления мышью?

...