Как запустить MouseEnter для одного объекта, если другой объект имеет mousecapture?
У меня странный вопрос и проект vb.net 2010 и wpf4. У меня есть метка, которая при щелчке захватывает мышь (MyLabel.captureMouse) и следует за ней по экрану до тех пор, пока мышь снова не щелкнет, после чего объект и захват мыши будут освобождены.
Тем не менее, мне все еще нужна функциональность mouseenter для другого объекта. Как мне заставить эти две вещи работать вместе?
РЕДАКТИРОВАТЬ: Есть два решения для этого, кажется, одно из которых я обнаружил. Однако, поскольку Рик должен работать также (хотя и не проверен из-за моего крайнего срока), и я ненавижу отвечать на свои собственные вопросы здесь, я принял его ответ.
В ожидании его комментария к проблеме, с которой я столкнулся, я нашел свое собственное решение. Таким образом, обязательно прочитайте и мой ответ, и ответ Рика.
3 ответа
Если другой объект является одним из ваших объектов, то ваша метка и другой объект могут взаимодействовать, пока вы захватываете мышь с использованием искусственных событий. Например, в вашем обработчике перемещения мыши вы можете проверить Mouse.DirectlyOver
чтобы увидеть, если это другой объект, и если так, сделайте небольшую бухгалтерию, а затем позвоните RaiseEvent
либо с MouseEnter
или же MouseLeave
на другом объекте. Если у вас есть куча этих объектов, вам просто нужно больше вести бухгалтерию.
Редактировать:
Вышесказанное относится к Mouse.DirectlyOver
который конкретно не работает, когда мышь захвачена. Чтобы сделать вышеупомянутое более конкретным и исправить эту ошибку, вот полный рабочий пример.
Вот разметка, показывающая холст, прямоугольник с обработкой захвата мыши и эллипс с обработкой ввода / вывода:
<Grid>
<Canvas>
<Rectangle Canvas.Left="0" Canvas.Top="0"
Fill="Red" Width="100" Height="100"
MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"
MouseMove="Rectangle_MouseMove"
MouseLeftButtonUp="Rectangle_MouseLeftButtonUp"/>
<Ellipse Canvas.Left="0" Canvas.Top="100"
Fill="Green" Width="100" Height="100"
MouseEnter="Ellipse_MouseEnter"
MouseLeave="Ellipse_MouseLeave">
<Ellipse.RenderTransform>
<ScaleTransform/>
</Ellipse.RenderTransform>
</Ellipse>
</Canvas>
</Grid>
и вот обработчики событий, которые демонстрируют, как генерировать искусственные события входа / выхода (но только для эллипса), пока мышь захвачена:
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var capturer = sender as FrameworkElement;
capturer.CaptureMouse();
}
bool over = false;
UIElement element;
private void Rectangle_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton != MouseButtonState.Pressed) return;
var capturer = sender as FrameworkElement;
var hit = VisualTreeHelper.HitTest(this, e.GetPosition(this));
if (hit == null) return;
var thisElement = hit.VisualHit as Ellipse;
var nowOver = thisElement != null;
if (nowOver) element = thisElement;
var args = new MouseEventArgs(Mouse.PrimaryDevice, 0);
if (!over && nowOver) { args.RoutedEvent = UIElement.MouseEnterEvent; element.RaiseEvent(args); }
if (over && !nowOver) { args.RoutedEvent = UIElement.MouseLeaveEvent; element.RaiseEvent(args); }
over = nowOver;
}
private void Rectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var capturer = sender as FrameworkElement;
capturer.ReleaseMouseCapture();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
Debug.WriteLine("MouseEnter");
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
Debug.WriteLine("MouseLeave");
}
Если вы запустите демо-версию под отладчиком, вы увидите, что обработчики ввода / вывода вызываются независимо от того, захвачена мышь или нет.
По моему опыту, использование Capturing не способ обработки перетаскиванием (если вы реализуете перетаскивание) именно из-за причины, которую вы здесь указали.
Я решаю эту ситуацию, отслеживая нажатие кнопки мыши и ее движение и перемещая элемент управления вперед.
Также возможно использовать поведение Blend Drag.
Поскольку код, который я использовал для имитации "перетаскивания" объекта, в любом случае требовал определения положения мыши, я воспользовался этой возможностью и написал код, который проверял, математически ли положение мыши на холсте находится в пределах границ каждого из объекты, для которых я нуждался в mouseenter/mouseleave. Это сработало особенно хорошо, так как объекты, в которых я нуждалась при наведении курсора мыши / отпускании мыши, никогда не менялись.
Вот урезанная версия моего окончательного кода.
'Declare the left, right, top, and bottom boundaries of each of the "drop-spot" objects in relation to the canvas. This could also be determined programamtically for objects that change position.
Private Tile1PosL As Double = 55
Private Tile1PosT As Double = 30
Private Tile2PosL As Double = 164
Private Tile2PosT As Double = 69
Private Tile3PosL As Double = 282
Private Tile3PosT As Double = 41
Private Tile4PosL As Double = 405
Private Tile4PosT As Double = 69
Private Tile5PosL As Double = 514
Private Tile5PosT As Double = 12
Private Sub Tile1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Tile1.MouseMove
If IsDragging1 = True Then
'My dragging functions go here.
'Get the mouse position on the canvas (canv).
Dim MousePosX As Double = e.GetPosition(canv).X
Dim MousePosY As Double = e.GetPosition(canv).Y
'Check to see if the mouse is within the boundaries of any of the "drop-spot" objects (Hole1, Hole2, Hole3, Hole4, Hole5).
If MousePosX > Hole1L And MousePosX < Hole1R And MousePosY > Hole1T And MousePosY < Hole1B Then
'Call the subroutine containing the code that would ordinarily go in "mouseenter".
Hole1_TileEnter()
ElseIf MousePosX > Hole2L And MousePosX < Hole2R And MousePosY > Hole2T And MousePosY < Hole2B Then
'Call the subroutine containing the code that would ordinarily go in "mouseenter".
Hole2_TileEnter()
ElseIf MousePosX > Hole3L And MousePosX < Hole3R And MousePosY > Hole3T And MousePosY < Hole3B Then
'Call the subroutine containing the code that would ordinarily go in "mouseenter".
Hole3_TileEnter()
ElseIf MousePosX > Hole4L And MousePosX < Hole4R And MousePosY > Hole4T And MousePosY < Hole4B Then
'Call the subroutine containing the code that would ordinarily go in "mouseenter".
Hole4_TileEnter()
ElseIf MousePosX > Hole5L And MousePosX < Hole5R And MousePosY > Hole5T And MousePosY < Hole5B Then
'Call the subroutine containing the code that would ordinarily go in "mouseenter".
Hole5_TileEnter()
Else
'If the mouse is not within any of the "drop-spot" objects, call the subroutine containing the code that would ordinarily go in each object's "mouseleave". NOTE: This code contains statements that determine that the mouse had been inside one of the "drop-spots" before actually triggering the rest of its code.
Hole_TileLeave()
End If
End If
End If
'This subroutine, with minor modifications, works for my Tile2, Tile3, Tile4, and Tile5 as well.
End Sub