Проверка дочерних элементов управления, добавленных на холст, не работает - PullRequest
2 голосов
/ 01 июня 2011

Я пытаюсь выполнить тестирование попаданий для коллекции пользовательских элементов управления, добавленных на холст во время выполнения.

Мой холст:

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

Я пробовал различные комбинации Carrier и LayoutRoot для GetPoint и FindElementsInHostCoordinates, но возвращаемые элементы всегда пусты.

Что я делаю не так?

Ответы [ 2 ]

7 голосов
/ 03 июня 2011

Есть несколько вещей, о которых вы должны знать о тестировании на попадание:

  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>

В качестве дополнительного совета не рекомендуется вкладывать панели холста, если для этого нет особой причины. Canvas - это специальная панель во многих отношениях, например, она не будет обрезать элементы, выходящие за ее пределы, по умолчанию она не имеет размера, если только вы ее не установите, и не является сплошным объектом, если вы не задали фон явно , Попробуйте использовать Grid и StackPanel для упорядочивания объектов и использовать холст только для определенного позиционирования только по координатам (x, y).

0 голосов
/ 01 июня 2011

Вы проверили UIElement.InputHitTest ? может быть стоит попробовать, если у вас проблемы с visualtreehelper

-edit-

Кроме того, вам, вероятно, следует использовать тот же элемент в вызове e.GetPosition (), что и в вызове VisualTreeHelper.FindElementsInHostCoordinates (), но вы пытались это сделать, я полагаю?

...