Problem with VisualTreeHelper.HitTest in WPF

Chris Nicol picture Chris Nicol · Aug 5, 2010 · Viewed 9.7k times · Source

I'm trying to hit-test a bunch of UserControls on a Canvas. I don't want the HitTest() to walk the whole way through the visual tree, so I'm using the FilterCallback to make sure I only hit-test the UserControl.

My problem is that the UserControl never hits, it should, but it doesn't. If I use the FilterCallback, I return that it hit nothing. If I let the HitTest run through the visual tree, it skips the UserControl.

Here's some code:

<Canvas x:Name="Container">
<UserControl>
   <Grid>
      <Rectangle />
   </Grid>
</UserControl>
<UserControl>
   <Grid>
      <Rectangle />
   </Grid>
</UserControl>
</Canvas>

...
VisualTreeHelper.HitTest(Container, OnFilter, OnResult, myPoint);
...

private void OnResult(DependencyObject o)
{
   //I'll get the Rectangle here, but never the userControl  
}

private void OnFilter(DependencyObject o)
{
   //I will get the UserControl here, but even when I do nothing more than continue, it will not trigger a visualHit.  But the child rectangle will.
}

Answer

Alex Paven picture Alex Paven · Aug 23, 2011

I know it's pretty damn late to answer this but here goes: a different approach is to override HitTestCore on the UserControl and provide it with the default behavior that would be expected from it:

protected override System.Windows.Media.HitTestResult HitTestCore(System.Windows.Media.PointHitTestParameters hitTestParameters)
{
    return new PointHitTestResult(this, hitTestParameters.HitPoint);
}

(of course you could complicate things and hit-test the actual children or the combination of their bounding boxes, but for me the bounding box of the user control was good enough; also, if you want to hit-test against geometry you need to override that second overload as well.)

This makes it work as expected, filtering out the children when using HitTestFilterBehavior.ContinueSkipChildren in the filter.