【问题标题】:Hit Test behavior命中测试行为
【发布时间】:2010-12-01 10:47:36
【问题描述】:

我有以下代码

public partial class MainWindow : Window
{
    public MainWindow() {
        InitializeComponent();
    }

    List<UIElement> ucs = new List<UIElement>();

    private void Window_PreviewMouseLeftButtonDown(object sender,
        MouseButtonEventArgs e)
    {
        ucs.Clear();

        Point p = e.GetPosition((UIElement)sender);

        VisualTreeHelper.HitTest(this, null,
            new HitTestResultCallback(MyHitTestCallback),
            new PointHitTestParameters(p));

        Console.WriteLine("ucs.Count = {0}", ucs.Count);

        foreach (var item in ucs)
        {
            Console.WriteLine("item: {0}", item.ToString());
        }
    }

    HitTestResultBehavior MyHitTestCallback(HitTestResult result)
    {
        ucs.Add(result.VisualHit as UIElement);
        return HitTestResultBehavior.Continue;
    }
}

这是我的窗户

<Window>
    <Grid>
        <my:UserControl1 HorizontalAlignment="Left" Margin="82,88,0,0" x:Name="userControl11" VerticalAlignment="Top" />
        <my:UserControl1 HorizontalAlignment="Left" Margin="168,166,0,0" x:Name="userControl12" VerticalAlignment="Top" />
        <my:UserControl1 HorizontalAlignment="Left" Margin="231,130,0,0" x:Name="userControl13" VerticalAlignment="Top" />
    </Grid>
</Window>

这是我的 UC

<UserControl>
    <Grid>
        <Label Content="Label" Height="44" HorizontalAlignment="Left" Name="label1" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" Width="78" Background="#FF4B9FC4" BorderBrush="#FF020A0D" BorderThickness="1" />
    </Grid>
</UserControl>

这是当我点击 ON A USER CONTROL,然后点击 2 UserControls 的交点时的输出:

ucs.Count = 2
item: System.Windows.Controls.Border
item: System.Windows.Controls.Border
ucs.Count = 3
item: System.Windows.Controls.Border
item: System.Windows.Controls.Border
item: System.Windows.Controls.Border

为什么会这样?鼠标实例下的UserControl在哪里?

PS:
现在,当我在标签上有 BorderThickness = 0

ucs.Count = 3
item: System.Windows.Controls.TextBlock
item: System.Windows.Controls.Border
item: System.Windows.Controls.Border
ucs.Count = 3
item: System.Windows.Controls.TextBlock
item: System.Windows.Controls.Border
item: System.Windows.Controls.Border

【问题讨论】:

    标签: .net wpf hittest


    【解决方案1】:

    UserControl1 是不可见的。它的 内容 是可见的,但您的 UserControl1 实例本身没有任何视觉效果。 (而且永远不会。用户控件的工作实际上只是包含其他内容。)

    命中测试仅报告对可视化树有直接贡献的元素。而且由于命中测试单独考虑每个元素,这意味着纯粹充当容器的元素不会出现。 (一个相关的事实是,命中测试只考虑实际绘制的像素。所以如果你有一个Border,你已经设置了BorderBrush和一个非零BorderThickness,但你没有Background , 命中测试只会将边界轮廓视为命中 - 边界内的点不会被视为命中边界,因为它没有在其内部绘制任何内容。

    如果您需要对“这个东西,或者这个东西里面的任何东西”样式进行命中测试,那么要么

    1. 使用鼠标进入/离开事件 - 那些气泡,因此即使在不可见的容器元素上它们也会被提升
    2. 使用IsMouseOver
    3. 使用您正在使用的命中测试函数,将用户控件作为第一个参数传递,并将任何命中视为命中测试点位于用户控件内部的指示

    第三个比较复杂,但如果您需要点击当前鼠标下的测试点以外的测试点,则需要使用它。

    【讨论】:

    • 我需要统计鼠标下的所有MyUserControls,直接或间接位于鼠标光标下。仅当元素直接在鼠标下方时,IsMouseOver 才会返回 true。
    • “间接”是什么意思? IsMouseOver 被记录为“包括在其范围内的可视子元素”。我想知道您是否正在寻找边界框包含,在这种情况下,命中测试是错误的。为此,您只需要 VisualTreeHelper.GetDescendantBounds。
    • ...或者换一种说法,我认为 WPF 命中测试可能与您想要的不同。您能否在不使用“命中测试”一词的情况下描述您想要做的事情,因为我认为该术语的歧义是造成混淆的原因。
    • 我的意思是如果我需要计算面板并且我将鼠标悬停在面板中的一个按钮上,则应该计算面板,就像其他最终的父面板一样。类似的问题:stackoverflow.com/questions/4323153/…
    • 我仍然不太清楚您要做什么。 “计数面板”听起来不像是用户驱动的要求。您的最终用户是否在敲门说“我们需要这个应用程序来计算面板!”?命中测试在 WPF 中有一些稍微令人惊讶的行为,这就是为什么我试图了解您在这里真正想要做什么。
    猜你喜欢
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    • 2011-04-30
    • 2014-05-30
    相关资源
    最近更新 更多