j'ai le contrôle de l'utilisateur suivant: un point et son nom:WPF UserControl HitTest
<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>
C'est cool.
Maintenant, j'ai un panneau, dans la sorcière je dois récupérer mes StopPoints que j'ai frappé avec la souris:
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;
}
}
}
Donc, comme vous pouvez le voir, le problème qui le HitTest identifie jamais un UserControl (StopPoint) comme il est, mais plutôt ses composants (TextBlock, Ellipse ou même Bordure). Comme j'associe l'objet métier à l'élément StopPoint, j'ai besoin de l'obtenir lors de MouseHitting, et non de ses éléments de composition.
Existe-t-il un moyen de le faire?
EDIT:
Utiliser le filtre (maintenant, il ne pénètre pas du tout dans le 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;
}
}
}
}
Avez-vous essayé d'ajouter un HitTestFilterCallback et de renvoyer ContinueSkipChildren s'il se trouve sur un StopPoint? Je vois que vous passez actuellement null comme rappel de filtre. – Bubblewrap
@Bubblewrap: hmm ... e ... que voulez-vous dire? – serhio
Le 2ème paramètre de VisualTreeHelper.HitTest, vous pouvez spécifier un HitTestFilterCallback. Voir ici: http://msdn.microsoft.com/en-us/library/ms752097.aspx # using_a_hit_test_filter_callback – Bubblewrap