Как запечатлеть события MouseMove под детьми управления
Вопрос
Я пытаюсь справиться с событием 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);
Относительно простой в использовании, и я могу поручиться за то, что он работает :)