如果另一个对象有鼠标捕获,如何为一个对象触发MouseEnter?

时间:2011-04-23 02:16:33

标签: wpf vb.net mouse

我有一个奇怪的问题和一个vb.net 2010和wpf4项目。我有一个标签,当点击它时,捕获鼠标(MyLabel.captureMouse)并在屏幕上跟随它,直到鼠标再次点击,此时对象和鼠标捕获被释放。

但是,我还需要将mouseenter的功能用于另一个对象。我如何让这两件事一起工作?

编辑:有两个解决方案,似乎是我发现的其中一个。但是,由于Rick应该也能正常工作(虽然因为我的截止日期未经测试),而且我讨厌在这里回答我自己的问题,所以我接受了他的回答。

在等待他回答我遇到的问题的过渡期间,我最终发现了自己的解决方案。因此,请务必阅读我的答案和Rick's。

3 个答案:

答案 0 :(得分:1)

如果另一个对象是您的某个对象,那么当您使用合成事件捕获鼠标时,您的标签和另一个对象可以合作。例如,在鼠标移动处理程序中,您可以检查Mouse.DirectlyOver以查看它是否是其他对象,如果是,请执行一些簿记,然后使用RaiseEvent或{MouseEnter来调用MouseLeave {1}}在另一个对象上。如果你有很多这些对象,那么你只需要做更多的簿记。

修改

以上是指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");
    }

如果你在调试器下运行demo,你会看到无论是否捕获了鼠标,都会调用enter / leave处理程序。

答案 1 :(得分:0)

在我使用捕获的经验中,处理拖放的方式(如果你正在实施拖放)正是因为你在这里说的原因。

我通过跟踪鼠标按钮和移动以及平移控件来解决这种情况。

也可以使用the Blend Drag behavior

答案 2 :(得分:0)

由于我使用的代码模拟对象的“拖动”无论如何都要涉及获取鼠标位置,我利用这个机会编写了一个代码,用于检查鼠标在画布上的位置是否在数学上在边界内我需要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