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