命中测试行为

发布于 2024-10-05 13:11:44 字数 2387 浏览 6 评论 0原文

我有以下代码

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>

这是我单击“用户控件”,然后单击 2 个用户控件的交集时的输出:

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

I have the following code

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

this is my window

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

this is my 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>

this is the output when I click ON A USER CONTROL, then on a intersection of 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

Why this? Where is the UserControl under the mouse instance?

PS:
Now, when I have on the Label the 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

乜一 2024-10-12 13:11:44

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

命中测试仅报告对可视化树有直接贡献的元素。由于命中测试孤立地考虑每个元素,这意味着纯粹充当容器的元素不会出现。 (一个相关的事实是,命中测试仅考虑实际绘制的像素。因此,如果您有一个设置了 BorderBrushBorder 和一个非零值, BorderThickness 但您没有 Background,命中测试只会将边框轮廓视为命中 - 边框内部的点不会被视为命中边框,因为它是 。

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

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

。一种更复杂,但如果您需要点击当前鼠标下方的测试点以外的测试点,则需要使用它。

The UserControl1 is invisible. Its contents are visible, but your UserControl1 instance itself does not have any visuals of its own. (And it never will. A user control's job is really just to contain other things.)

Hit testing only reports elements that make a direct contribution to the visual tree. And since hit testing considers each element in isolation, this means that elements that are acting purely as containers don't show up. (And a related fact is that hit testing only considers the pixels that actually got painted. So if you have a Border where you've set the BorderBrush and a non-zero BorderThickness but you have no Background, the hit test will only consider the border outline to be a hit - points inside of the border will not be considered to hit the border because it's not painting anything in its interior.

If you need to do hit testing of a "this thing, or anything inside this thing" style, then either either

  1. use mouse enter/leave events - those bubble, and so they will get raised even on invisible container elements
  2. use IsMouseOver or
  3. use the hit test function you're using, passing the user control as the first argument, and treat any hit as an indication that the hit test point is inside the user control

The third one is more complex, but if you need to hit test points other than the one currently under the mouse, you'd need to use it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文