C#, WPF – Hit Testing Example

When we create interactive 2D drawing applications in WPF, we can deal directly with the user’s
interaction with the graphics objects using mouse event handlers. However, WPF provides powerful hit-
testing for graphics objects through the static VisualTreeHelper.HitTest method.
In order to use this advanced hit-testing feature, we need to create a callback. The VisualTreeHelper
will then walk through your visuals from top to bottom. Whenever it finds a match, it calls the callback
with the details. We can then choose to stop the search or to continue until no more visuals remain
.
The following example will illustrate how to use this advanced feature. In this example we have many rectangles overlapping with each other, when we click on a point on windows there is a popup telling us at point how many rectangles are locating.
Use Microsoft Expression Blend to draw many overlapped rectangle as proposed as below.

Name our grid as grdMain and add handler for MouseLeftButtonDown.

<Grid x:Name="grdMain" MouseLeftButtonDown="cvMain_MouseLeftButtonDown">

In the function cvMain_MouseLeftButtonDown, we define the hit area and call the function VisualTreeHelper.HitTest to find out the intersection area between our hit area and painted rectangle

private void cvMain_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
	Point ptCurrent = e.GetPosition(grdMain);
	m_egHitArea = new EllipseGeometry(ptCurrent, 1, 1);
	m_lstHitList.Clear();
	VisualTreeHelper.HitTest(grdMain, null, new HitTestResultCallback(HitTestCallback), new GeometryHitTestParameters(m_egHitArea));
	if (m_lstHitList.Count > 0)
	{
		MessageBox.Show("You hit " + m_lstHitList.Count + " rectangles");
	}
}

We have expanded our hit-test area using an EllipseGeometry. When the user clicks on the grid, the program starts the hit-test process by calling HitTestCallback. The VisualTreeHelper will then walk through visuals from top to bottom. If it hits any rectangle,the rectangle will be added to m_lstHitList.

public HitTestResultBehavior HitTestCallback(HitTestResult htrResult)
{
	IntersectionDetail idDetail = ((GeometryHitTestResult)htrResult).IntersectionDetail;
	switch (idDetail)
	{
		case IntersectionDetail.FullyContains:
			m_lstHitList.Add((Rectangle)htrResult.VisualHit);
			return HitTestResultBehavior.Continue;
		case IntersectionDetail.Intersects:
			return HitTestResultBehavior.Continue;
		case IntersectionDetail.FullyInside:
			return HitTestResultBehavior.Continue;
		default:
			return HitTestResultBehavior.Stop;
	}
}

Usually, the HitTestResult object provides just a single property (VisualHit), but we can cast it to one of two derived types, depending on the type of hit-test we’re performing.
If we’re hit-testing a point, we can cast HitTestResult to PointHitTestResult, which provides a
PointHit property that returns the original point you used to perform the hit-test. If you are hit-testing a
Geometry object (or shape), as you are in this example, you can cast HitTestResult to
GeometryHitTestResult and get access to the IntersectionDetail property as example above.

The complete source code of this example you can download “Hit Testing Example

This example I extracted from book “Practical WPF Charts and Graphics“. Password: 4aedF0xFZN0BBPE

One thought on “C#, WPF – Hit Testing Example”

  1. Great example…

    But how can I find that cursor hit on DataGrid Column Header???
    I need to display Column header name..

    Thanks in advance

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>