添加到画布的命中测试子控件不起作用 [英] Hit testing child controls added to a canvas does not work

查看:12
本文介绍了添加到画布的命中测试子控件不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对运行时添加到画布的一组用户控件执行点击测试。

我的画布:

<Canvas x:Name="LayoutRoot" Background="White">
    <Canvas  x:Name="Carrier" Canvas.ZIndex="-1">
    </Canvas>
</Canvas>

我的画布代码:

    public MainPage()
    {
        InitializeComponent();

        var uiElement = new MyUserControl();
        this.Carrier.Children.Add(uiElement);

        MouseLeftButtonDown += MouseLeftButtonDownHandler;
    }

    private List<UIElement> HitSprite(Point p)
    {
        var hitElements = 
           VisualTreeHelper.FindElementsInHostCoordinates(p, this.Carrier) as List<UIElement>;

        return hitElements.Count > 0 ? hitElements : null;
    }

    private void MouseLeftButtonDownHandler(object sender, MouseButtonEventArgs e)
    {
        var list = HitSprite(e.GetPosition(this.LayoutRoot));
    }

我的用户控件:

<Canvas x:Name="Container" AllowDrop="True">
    <StackPanel Name="Description" Height="65" Canvas.ZIndex="2" IsHitTestVisible="False">
        <TextBlock Text="Testing" x:Name="Name" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" IsHitTestVisible="False"/>

        <Border Background="Green">
            <Image x:Name="Body" Stretch="None" Canvas.ZIndex="0" Height="20" Width="20">
            </Image>
        </Border>
    </StackPanel>
</Canvas>

我尝试了GetPoint和FindElementsInHostOrganates的Carrier和LayoutRoot的各种组合,但返回的元素始终为空。

我做错了什么?

推荐答案

关于点击测试,您必须注意几件事:

  1. 没有背景的元素不会出现在点击测试中,因此请设置背景,甚至将其设置为透明工作。之所以会发生这种情况,是因为对象需要是"实心的"才能进行命中测试。
  2. 没有宽度和高度的元素不会出现在命中测试中,因为它们没有要命中的正文。
  3. IsHitTestVisible=False的元素不会出现在命中测试中,它们已被显式排除在测试之外。

在您的情况下,这些因素的组合使您的用户控件对命中测试不可见:

  1. 您的用户控件不可靠,它没有背景。
  2. 在用户控件中用作布局根的画布没有设置大小,因此宽度和高度为零。它也没有背景。
  3. 用户控件中的所有子元素的IsHitTestVisible=False,这会显式地将它们从命中测试中排除。

我对您的用户控件XAML和后面的代码做了几处修改,现在我在点击测试结果中看到了您的用户控件:

    public MainPage()
    {
        // Required to initialize variables
        InitializeComponent();

        var uiElement = new MyUserControl();
        this.Carrier.Children.Add(uiElement);

        MouseLeftButtonDown += MouseLeftButtonDownHandler;
    }
    private List<UIElement> HitSprite(Point p)
    {
        var hitElements =
           VisualTreeHelper.FindElementsInHostCoordinates(p, this.LayoutRoot) as List<UIElement>;

        return hitElements.Count > 0 ? hitElements : null;
    }

    private void MouseLeftButtonDownHandler(object sender, MouseButtonEventArgs e)
    {
        var list = HitSprite(e.GetPosition(this.LayoutRoot));
    }

XAML:

<Grid x:Name="Container" AllowDrop="True" Background="Transparent">
    <StackPanel Name="Description" Height="65" Canvas.ZIndex="2" IsHitTestVisible="False">
        <TextBlock Text="Testing" x:Name="Name" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" IsHitTestVisible="False"/>

        <Border Background="Green">
            <Image x:Name="Body" Stretch="None" Canvas.ZIndex="0" Height="20" Width="20">
            </Image>
        </Border>
    </StackPanel>
</Grid>

作为补充建议,除非有特定原因,否则嵌套画布面板不是一个好主意。画布在许多方面都是一个特殊的面板,例如,它不会剪裁超出其边界的项目,默认情况下它没有大小,除非您设置一个大小,而且除非您显式设置背景,否则它不是实体对象。尝试使用网格和StackPanel来排列对象,并使用画布仅在(x,y)坐标上进行特定定位。

这篇关于添加到画布的命中测试子控件不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆