在WPF中用鼠标检测儿童控件

时间:2012-04-17 15:50:56

标签: .net wpf vb.net wpf-controls

我有一个WPF ParentUserControl和一些ChildUserControlA ChildUserControlB等(也是WPF控件)

ChildUserControl是包含一些其他基本元素(文本框,标签等)的控件

在主窗体的状态栏中,我需要显示当前鼠标的名称​​ ChildUserControl

所以,在 ParentUserControl 的MouseMove中,我获得了一个对象myElement = Mouse.DirectlyOver,因为我需要 ChildUserControl 的最顶层,但我获得的是'System.Windows.Controls.TextBlock'(ChildUserControl的一部分)......

如何解决这个问题?

当我在MyChildControl上鼠标时,我需要检测到MyChildControl,而不是它的子元素。

按照这个顺序,我在MyChildControl上使用了以下内容:

Protected Overrides Function HitTestCore(
                    hitTestParameters As PointHitTestParameters) As HitTestResult

    Return New PointHitTestResult(Me, hitTestParameters.HitPoint)
End Function

但无论如何我有时会得到文本块,有时是ChildUserControl ......

2 个答案:

答案 0 :(得分:3)

您需要实施Hit-Testing。因此,如果您想获取区域内的所有元素,可以使用HitTestResultCallback。一个例子:

Dim Elements As New List(Of FrameworkElement)


Public Function GetVisuals(ByVal Region As Geometry) As List(Of FrameworkElement)

    If Region Is Nothing Then Return Nothing

    Dim Parameters As New GeometryHitTestParameters(Region)
    Elements.Clear()

    Dim Callback As New HitTestResultCallback(AddressOf Me.HitTestCallBack)
    VisualTreeHelper.HitTest(Me.ParentUserControl, Nothing, Callback, Parameters)

    Return Me.Elements

End Function

Private Function HitTestCallBack(ByVal Result As HitTestResult) As HitTestResultBehavior

    If Result IsNot Nothing Then

        Dim GeometryRes As GeometryHitTestResult = CType(Result, GeometryHitTestResult)
        Dim Element As FrameworkElement = TryCast(Result.VisualHit, FrameworkElement)

        If Element IsNot Nothing AndAlso GeometryRes.IntersectionDetail = IntersectionDetail.FullyContains Then
            Me.Elements.Add(Element)
        End If

    End If

    Return HitTestResultBehavior.Continue

End Function

这样,Elements列表包含GeometryHitTestResult.IntersectionDetail指定的所有元素,如果你想(例如)知道鼠标位置下的元素(MouseDown Event),只需这样做:

Dim Region As New RectangleGeometry(New Rect(e.GetPosition(Me.MyGrid), New Size(1, 1)))
Dim Elements As List(Of FrameworkElement) = Me.GetVisuals(Region)

这就是我在评论中的意思:

Public Class DrawingCanvas
Inherits Panel

Public Function GetVisuals(ByVal Region As Geometry) As List(Of DrawingVisual)
End Function

Private Function HitTestCallBack(ByVal Result As HitTestResult) As HitTestResultBehavior
End Function

End Class

答案 1 :(得分:1)

另一个答案可能是这样的 - 定义你关心的对象的确切类型,然后处理可视树,直到找到它们为止:

Private myTypes As New List(Of Type)()
Public Sub New()
    InitializeComponent()
    myTypes.Add(GetType(ComboBox))
    myTypes.Add(GetType(CheckBox))
    myTypes.Add(GetType(RadioButton))
    myTypes.Add(GetType(TabControl))
    myTypes.Add(GetType(Button))
    myTypes.Add(GetType(Label))
    myTypes.Add(GetType(GroupBox))
    myTypes.Add(GetType(Window))
End Sub

Private Sub Window_MouseMove(sender As Object, e As MouseEventArgs)
    Dim x As DependencyObject = _
      DirectCast(e.MouseDevice.DirectlyOver, DependencyObject)
    Dim t As Type = x.GetType
    While Not myTypes.Contains(t)
         x = VisualTreeHelper.GetParent(x)
         If x Is Nothing Then Exit While
         t = x.GetType
    End While

    If x IsNot Nothing Then
          Console.WriteLine(x.ToString())
    Else
          Console.WriteLine("Nothing")
    End If
End Sub