WPF UIElement.IsHitTestVisible=false; still returning hits?
Asked Answered
A

1

11

I'm deriving a control from FrameworkElement to use as a container for a VisualCollection, as I'm doing a lot of custom rendering using DrawingVisuals (creating a game map).

I've got a couple different instances of my container layered on top of each other, and I only want hit testing to affect the layer currently visible, so I tried doing the obvious, and set .IsHitTestVisible=false, which according to MSDN should prevent any child elements being returned as hit results.

However, I am still getting hits returned on the containers that are set .IsHitTestVisible=false. I've tried everything else I can think of, Collapsed, Hidden, Disabled, 0 Opacity, nothing seems to take it out of the hit testing.

Attainment answered 27/1, 2011 at 6:34 Comment(1)
The only workaround I've found so far is to actually remove the container control from it's parent collection, so that it's completely out of the VisualTree hierarchy.Attainment
F
14

I think it's a bug. I used Reflector to understand why the HitTest method returns invisible items and I have found that there is no check for visibility.

My solution is to use overload HitTest with filter:

public static HitTestFilterBehavior HitTestFilterInvisible(DependencyObject potentialHitTestTarget)
{
    bool isVisible = false;
    bool isHitTestVisible = false;

    var uiElement = potentialHitTestTarget as UIElement;
    if (uiElement != null)
    {
        isVisible = uiElement.IsVisible;
        if (isVisible)
        {
            isHitTestVisible = uiElement.IsHitTestVisible;
        }
    }
    else
    {
        UIElement3D uiElement3D = potentialHitTestTarget as UIElement3D;
        if (uiElement3D != null)
        {
            isVisible = uiElement3D.IsVisible;
            if (isVisible)
            {
                isHitTestVisible = uiElement3D.IsHitTestVisible;
            }
        }
    }

    if (isVisible)
    {
        return isHitTestVisible ? HitTestFilterBehavior.Continue : HitTestFilterBehavior.ContinueSkipSelf;
    }

    return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
}
...
// usage:

    VisualTreeHelper.HitTest(
        myHitTestReference,
        HitTestFilterInvisible,
        hitTestResult =>
        {
            // code to handle element which is visible to the user and enabled for hit testing.
        },
        new PointHitTestParameters(myHitTestPoint));

I hope it will help you

Futurism answered 27/1, 2011 at 7:0 Comment(2)
Although I was hoping for a way to make the behavior work as MSDN describes rather than a workaround, this was helpful so I'll mark it as the answer.Attainment
I am having the same issue with a border that is part of my scrollviewer template... I have a border at the bottom that creates a little "hint" shadow so the user knows the content is scrollable, but the border is blocking mouse events from the content underneath it... I have set IsHitTestVisible="false" on the border but it still gets mouse events. Unfortunately I am not dealing with any code behind files so I can't override the hit test methods... any ideas?Schwerin

© 2022 - 2024 — McMap. All rights reserved.