Silverlight Quick Tip: How to Perform a Hit Test
In some cases, especially when developing rich UI application developer need to identify which control were clicked or under mouse pointer at some point of time or just under some coordinate at the UI. For those purposes Silverlight provides “FindElementsInHostCoordinates” function in VisualTreeHelper class.
The function gets the Point (coordinate on the screen) or Rect (rectangular area) and UIElement which will be checked recursively to have any visual child's in desired coordinate/area. The function returns IEnumerable<UIElement>.
In most cases, especially when using custom controls the returned list will have many UIElements. They need to be filtered out.
For the sample I’ve created the Custom Control with default style/template:
<Style TargetType="local:SampleControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SampleControl">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}">
<StackPanel Orientation="Vertical">
<Path Fill="{TemplateBinding Background}" Stretch="Uniform" StrokeThickness="3"
Stroke="{TemplateBinding BorderBrush}" Height="43.5" UseLayoutRounding="False"
Data="M21,36 C55, ..., 75.500374z"/>
<TextBlock Text="{TemplateBinding SmapleStringProperty}" TextWrapping="Wrap"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

The control is pretty empty – created 3 Dependency Properties, for store some Boolean, Integer and String data (see in sample here).
For the test page I’ve created function to initialize the number of such controls randomly and subscribed to “MouseLeftButtonDown” event on main canvas
In sample case, I wanted to show the list of controls, with Boolean value == true (in initialization each control got True in case its number was odd, and False if it vas even) and show them in report.
First, to get the list of controls under my mouse pointer at the time of event:
List<UIElement> list = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null),
LayoutRoot as UIElement) as List<UIElement>;
Even in case of single control click my list returns with 5 elements (in case of click on overlapped controls it is even more)
To filter out only the SampleControl, which also has Boolean property with desired value I used LINQ:
var selectedControls = from control in list
where control is SampleControl && (control as SampleControl).SampleBoolProperty
select control as SampleControl;
In case I have controls I’m looking for I could get them and process according to my business loginc
if (selectedControls.Count() > 0)
foreach (var selectedControl in selectedControls)
...
That’s it – got the list of the controls under the desired point.
Sample source here.
Running sample here.
Enjoy,
Alex