I have the following user control: a dot and its name:
<UserControl x:Class="ShapeTester.StopPoint"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="100">
<StackPanel>
<Ellipse Stroke="DarkBlue" Fill="LightBlue" Height="10" Width="10"/>
<TextBlock Text="Eiffel Tower"/>
</StackPanel>
</UserControl>
This is cool.
Now, I have a panel, in witch I need to recuperate my StopPoints that I hit with the Mouse:
public partial class StopsPanel : UserControl
{
private List<StopPoint> hitList = new List<StopPoint>();
private EllipseGeometry hitArea = new EllipseGeometry();
public StopsPanel()
{
InitializeComponent();
Initialize();
}
private void Initialize()
{
foreach (StopPoint point in StopsCanvas.Children)
{
point.Background = Brushes.LightBlue;
}
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Initialization:
Initialize();
// Get mouse click point:
Point pt = e.GetPosition(StopsCanvas);
// Define hit-testing area:
hitArea = new EllipseGeometry(pt, 1.0, 1.0);
hitList.Clear();
// Call HitTest method:
VisualTreeHelper.HitTest(StopsCanvas, null,
new HitTestResultCallback(HitTestCallback),
new GeometryHitTestParameters(hitArea));
if (hitList.Count > 0)
{
foreach (StopPoint point in hitList)
{
// Change rectangle fill color if it is hit:
point.Background = Brushes.LightCoral;
}
MessageBox.Show(string.Format(
"You hit {0} StopPoint(s)", hitList.Count));
}
}
public HitTestResultBehavior HitTestCallback(HitTestResult result)
{
if (result.VisualHit is StopPoint)
{
//
//-------- NEVER ENTER HERE!!! :(
//
// Retrieve the results of the hit test.
IntersectionDetail intersectionDetail =
((GeometryHitTestResult)result).IntersectionDetail;
switch (intersectionDetail)
{
case IntersectionDetail.FullyContains:
// Add the hit test result to the list:
hitList.Add((StopPoint)result.VisualHit);
return HitTestResultBehavior.Continue;
case IntersectionDetail.Intersects:
// Set the behavior to return visuals at all z-order levels:
return HitTestResultBehavior.Continue;
case IntersectionDetail.FullyInside:
// Set the behavior to return visuals at all z-order levels:
return HitTestResultBehavior.Continue;
default:
return HitTestResultBehavior.Stop;
}
}
else
{
return HitTestResultBehavior.Continue;
}
}
}
So, as you can see, the problem that the HitTest never identifies an UserControl(StopPoint) as it is, but rather its components(TextBlock, Ellipse or even Border).
As I associate the business object to the StopPoint element, I need to obtain it when MouseHitting, and not its composing elements.
Is there a way to do it?
EDIT:
Using filter (now, it does not enter at all in the HitTestCallback):
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace ShapeTester
{
/// <summary>
/// Interaction logic for StopsPanel.xaml
/// </summary>
public partial class StopsPanel : UserControl
{
private List<StopPoint> hitList = new List<StopPoint>();
private EllipseGeometry hitArea = new EllipseGeometry();
public StopsPanel()
{
InitializeComponent();
Initialize();
}
private void Initialize()
{
foreach (StopPoint point in StopsCanvas.Children)
{
point.Background = Brushes.LightBlue;
}
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Initialization:
Initialize();
// Get mouse click point:
Point pt = e.GetPosition(StopsCanvas);
// Define hit-testing area:
hitArea = new EllipseGeometry(pt, 1.0, 1.0);
hitList.Clear();
// Call HitTest method:
VisualTreeHelper.HitTest(StopsCanvas,
new HitTestFilterCallback(MyHitTestFilter),
new HitTestResultCallback(HitTestCallback),
new GeometryHitTestParameters(hitArea));
if (hitList.Count > 0)
{
foreach (StopPoint point in hitList)
{
// Change rectangle fill color if it is hit:
point.Background = Brushes.LightCoral;
}
MessageBox.Show(string.Format(
"You hit {0} StopPoint(s)", hitList.Count));
}
}
public HitTestResultBehavior HitTestCallback(HitTestResult result)
{
if (result.VisualHit is StopPoint)
{
//
//-------- NEVER ENTER HERE!!! :(
//
// Retrieve the results of the hit test.
IntersectionDetail intersectionDetail =
((GeometryHitTestResult)result).IntersectionDetail;
switch (intersectionDetail)
{
case IntersectionDetail.FullyContains:
// Add the hit test result to the list:
hitList.Add((StopPoint)result.VisualHit);
return HitTestResultBehavior.Continue;
case IntersectionDetail.Intersects:
// Set the behavior to return visuals at all z-order levels:
return HitTestResultBehavior.Continue;
case IntersectionDetail.FullyInside:
// Set the behavior to return visuals at all z-order levels:
return HitTestResultBehavior.Continue;
default:
return HitTestResultBehavior.Stop;
}
}
else
{
return HitTestResultBehavior.Continue;
}
}
// Filter the hit test values for each object in the enumeration.
public HitTestFilterBehavior MyHitTestFilter(DependencyObject o)
{
// Test for the object value you want to filter.
if (o.GetType() == typeof(StopPoint))
{
// Visual object's descendants are
// NOT part of hit test results enumeration.
return HitTestFilterBehavior.ContinueSkipChildren;
}
else
{
// Visual object is part of hit test results enumeration.
return HitTestFilterBehavior.Continue;
}
}
}
}