protected override Visual GetVisualChild(int index)
{
// Значение должно быть больше нуля, поэтому разумно это проверить.
if (index < 0 || index >= theVisuals.Count)
{
throw new ArgumentOutOfRangeException();
}
return theVisuals[index];
}
Теперь вы располагаете достаточной функциональностью, чтобы протестировать специальный класс. Модифицируйте описание XAML элемента Window, добавив в существующий контейнер StackPanel один объект CustomVisualFrameworkElement. Это потребует создания специального пространства имен XML, которое отображается на пространство имен .NET Core.
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RenderingWithVisuals"
Title="Fun with the Visual Layer" Height="350" Width="525"
Loaded="Window_Loaded" WindowStartupLocation="CenterScreen">
Результат выполнения программы показан на рис. 26.15.
Реагирование на операции проверки попадания
Поскольку класс DrawingVisual не располагает инфраструктурой UIElement или FrameworkElement, необходимо программно добавить возможность реагирования на операции проверки попадания. Благодаря концепции логического и визуального деревьев на визуальном уровне делать это очень просто. Оказывается, что в результате написания блока XAML по существу строится логическое дерево элементов. Однако с каждым логическим деревом связано намного более развитое описание, известное как визуальное дерево, которое содержит низкоуровневые инструкции визуализации.
Упомянутые деревья подробно рассматриваются в главе 27, а сейчас достаточно знать, что до тех пор, пока специальные визуальные объекты не будут зарегистрированы в таких структурах данных, выполнять операции проверки попадания невозможно. К счастью, контейнер VisualCollection обеспечивает регистрацию автоматически (вот почему в аргументе конструктора необходимо передавать ссылку на специальный элемент FrameworkElement).
Измените код класса CustomVisualFrameworkElement для обработки события MouseDown в конструкторе класса с применением стандартного синтаксиса С#:
this.MouseDown += CustomVisualFrameworkElement_MouseDown;
Реализация данного обработчика будет вызывать метод VisualTreeHelper.HitTest() с целью выяснения, находится ли курсор мыши внутри границ одного из визуальных объектов. Для этого в одном из параметров метода HitTest() указывается делегат HitTestResultCallback, который будет выполнять вычисления. Добавьте в класс CustomVisualFrameworkElement следующие методы:
void CustomVisualFrameworkElement_MouseDown(object sender, MouseButtonEventArgs e)
{
// Выяснить, где пользователь выполнил щелчок.
Point pt = e.GetPosition((UIElement)sender);
// Вызвать вспомогательную функцию через делегат, чтобы
// посмотреть, был ли совершен щелчок на визуальном объекте.
VisualTreeHelper.HitTest(this, null,
new HitTestResultCallback(myCallback), new PointHitTestParameters(pt));
}
public HitTestResultBehavior myCallback(HitTestResult result)
{
// Если щелчок был совершен на визуальном объекте, то
// переключиться между скошенной и нормальной визуализацией.
if (result.VisualHit.GetType() == typeof(DrawingVisual))
{
if (((DrawingVisual)result.VisualHit).Transform == null)
{
((DrawingVisual)result.VisualHit).Transform = new SkewTransform(7, 7);
}
else
{
((DrawingVisual)result.VisualHit).Transform = null;
}
}