Как запечатлеть события MouseMove под детьми управления

StackOverflow https://stackoverflow.com/questions/1719636

Вопрос

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

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

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

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

Это было полезно?

Решение

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

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

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

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

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

Лучший, Билл

Другие советы

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

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);
    }
}

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

Application.AddMessageFilter(this);

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

Вам, вероятно, нужно использовать P/invoke для метода Win32 Ischild

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

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

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

Я знаю, что я немного опоздал на удар, но у меня были проблемы с этим ранее сегодня, когда я использовал панель в качестве строки заголовка. У меня была метка, чтобы отобразить немного текста, изображение и несколько кнопок, все вложенные в панели, но мне нужно было поймать событие 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);
        }
    }

А затем настроите подписчики события Controls:

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top