gpt4 book ai didi

WPF 用户控件 HitTest

转载 作者:行者123 更新时间:2023-12-04 16:18:04 29 4
gpt4 key购买 nike

我有以下用户控件:一个点及其名称:

<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>

这很酷。

现在,我有一个面板,我需要恢复我用鼠标击中的停止点:

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;
}
}
}

因此,如您所见,HitTest 从来没有识别出 UserControl(StopPoint) 的问题,而是识别出它的组件(TextBlock, 椭圆甚至边框)。
当我将业务对象关联到 StopPoint 元素时,我需要在 MouseHitting 时获取它,而不是它的组成元素。

有办法吗?

编辑:

使用过滤器(现在,它根本不进入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;
}
}
}
}

最佳答案

我想写一个解释,但我已经找到了一个不错的解释:

https://stackoverflow.com/a/7162443/717732

重点是:

您的 UserControl.HitTestCore() 留给可能返回 NULL 的默认实现,这会导致 UC 被跳过而不是传递给 resultCallback。

默认行为不是错误。这是一个不明显的、聪明的设计——总而言之,你的控件没有视觉效果,它只是一些有形状的 child 的容器,所以通常在 UC 中没有必要被击中并弄乱人行道。您可能会将其视为一个缺点,因为您的代码的简洁性可能会受益于 UC 的可测试性。然而,这里的目标不是简洁,而是速度。事实上,这是一个重要的特性,因为它确实减少了 treewalker 必须执行实际交叉点的项目数量!

所以 - 要么实现 HitTestCore 并返回非空值,要么为 UserControl 的子级进行 HitTest ,然后当得到正确的结果但等于它的子级时,使用 VisualTreeHelper.GetParent 直到你走到你想要的 UserControl .

关于WPF 用户控件 HitTest ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3745910/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com