Поделиться через


Использование объектов DrawingVisual

В этом разделе представлен обзор использования объектов DrawingVisual в визуальном слое WPF.

Объект DrawingVisual

DrawingVisual — это упрощенный класс рисования, используемый для отрисовки фигур, изображений или текста. Этот класс считается упрощенным, так как он не предоставляет разметку или обработку событий, что повышает его производительность. По этой причине рисунки идеально подходят для фона и картинок.

Контейнер хостинга Visual Drawing

Чтобы использовать объекты DrawingVisual, необходимо создать контейнер узла для объектов. Объект контейнера узла должен быть производным от класса FrameworkElement, который предоставляет поддержку разметки и обработки событий, отсутствующую в классе DrawingVisual. Объект-контейнер не отображает видимые свойства, так как его основная цель — содержать дочерние объекты. Однако свойство Visibility контейнера хоста должно иметь значение Visible; в противном случае не будет отображаться ни один из дочерних элементов.

При создании объекта контейнера узла для визуальных объектов необходимо хранить ссылки на визуальные объекты в VisualCollection. Используйте метод Add для добавления визуального объекта в контейнер узла. В следующем примере создается объект контейнера-хоста, а три визуальных объекта добавляются в его VisualCollection.

// Create a host visual derived from the FrameworkElement class.
// This class provides layout, event handling, and container support for
// the child visual objects.
public class MyVisualHost : FrameworkElement
{
    // Create a collection of child visual objects.
    private VisualCollection _children;

    public MyVisualHost()
    {
        _children = new VisualCollection(this);
        _children.Add(CreateDrawingVisualRectangle());
        _children.Add(CreateDrawingVisualText());
        _children.Add(CreateDrawingVisualEllipses());

        // Add the event handler for MouseLeftButtonUp.
        this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MyVisualHost_MouseLeftButtonUp);
    }
' Create a host visual derived from the FrameworkElement class.
' This class provides layout, event handling, and container support for
' the child visual objects.
Public Class MyVisualHost
    Inherits FrameworkElement
    ' Create a collection of child visual objects.
    Private _children As VisualCollection

    Public Sub New()
        _children = New VisualCollection(Me)
        _children.Add(CreateDrawingVisualRectangle())
        _children.Add(CreateDrawingVisualText())
        _children.Add(CreateDrawingVisualEllipses())

        ' Add the event handler for MouseLeftButtonUp.
        AddHandler MouseLeftButtonUp, AddressOf MyVisualHost_MouseLeftButtonUp
    End Sub

Заметка

Полный пример кода, из которого был извлечен предыдущий пример кода, см. в разделе Тест попадания с помощью примера DrawingVisuals.

Создание объектов DrawingVisual

При создании объекта DrawingVisual он не содержит графического содержимого. Вы можете добавить текст, графику или содержимое изображения, извлекая DrawingContext объекта и рисуя в него. Возвращается DrawingContext в результате вызова метода RenderOpen объекта DrawingVisual.

Чтобы нарисовать прямоугольник в DrawingContext, используйте метод DrawRectangle объекта DrawingContext. Аналогичные методы существуют для рисования других типов содержимого. После завершения рисования содержимого в DrawingContextвызовите метод Close, чтобы закрыть DrawingContext и сохранить содержимое.

В следующем примере создается объект DrawingVisual, а прямоугольник рисуется в DrawingContext.

// Create a DrawingVisual that contains a rectangle.
private DrawingVisual CreateDrawingVisualRectangle()
{
    DrawingVisual drawingVisual = new DrawingVisual();

    // Retrieve the DrawingContext in order to create new drawing content.
    DrawingContext drawingContext = drawingVisual.RenderOpen();

    // Create a rectangle and draw it in the DrawingContext.
    Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
    drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);

    // Persist the drawing content.
    drawingContext.Close();

    return drawingVisual;
}
' Create a DrawingVisual that contains a rectangle.
Private Function CreateDrawingVisualRectangle() As DrawingVisual
    Dim drawingVisual As New DrawingVisual()

    ' Retrieve the DrawingContext in order to create new drawing content.
    Dim drawingContext As DrawingContext = drawingVisual.RenderOpen()

    ' Create a rectangle and draw it in the DrawingContext.
    Dim rect As New Rect(New Point(160, 100), New Size(320, 80))
    drawingContext.DrawRectangle(Brushes.LightBlue, CType(Nothing, Pen), rect)

    ' Persist the drawing content.
    drawingContext.Close()

    Return drawingVisual
End Function

Создание переопределений для членов FrameworkElement

Объект контейнера узла отвечает за управление коллекцией визуальных объектов. Для этого требуется, чтобы контейнер-хост реализовал переопределения методов для производного класса FrameworkElement.

В следующем списке описаны два элемента, которые необходимо переопределить:

  • GetVisualChild: возвращает элемент-потомок по указанному индексу из коллекции элементов-потомков.

  • VisualChildrenCount: возвращает количество визуальных дочерних элементов в этом элементе.

В следующем примере реализуются переопределения для двух членов FrameworkElement.


// Provide a required override for the VisualChildrenCount property.
protected override int VisualChildrenCount
{
    get { return _children.Count; }
}

// Provide a required override for the GetVisualChild method.
protected override Visual GetVisualChild(int index)
{
    if (index < 0 || index >= _children.Count)
    {
        throw new ArgumentOutOfRangeException();
    }

    return _children[index];
}


' Provide a required override for the VisualChildrenCount property.
Protected Overrides ReadOnly Property VisualChildrenCount() As Integer
    Get
        Return _children.Count
    End Get
End Property

' Provide a required override for the GetVisualChild method.
Protected Overrides Function GetVisualChild(ByVal index As Integer) As Visual
    If index < 0 OrElse index >= _children.Count Then
        Throw New ArgumentOutOfRangeException()
    End If

    Return _children(index)
End Function

Предоставление поддержки определения попаданий

Объект контейнера узла может обеспечить обработку событий, даже если он не отображает видимые свойства, однако его свойство Visibility должно иметь значение Visible. Это позволяет вам создать подпрограмму обработки событий для контейнера-хоста, способного перехватывать события мыши, например, выпуск левой кнопки мыши. Подпрограмма обработки событий затем может реализовать проверку попаданий, вызвав метод HitTest. Параметр HitTestResultCallback метода ссылается на определяемую пользователем процедуру, которую можно использовать для определения результирующего действия хит-теста.

В следующем примере поддержка тестирования попаданий реализуется для хост-контейнерного объекта и его дочерних объектов.

// Capture the mouse event and hit test the coordinate point value against
// the child visual objects.
void MyVisualHost_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    // Retrieve the coordinates of the mouse button event.
    System.Windows.Point pt = e.GetPosition((UIElement)sender);

    // Initiate the hit test by setting up a hit test result callback method.
    VisualTreeHelper.HitTest(this, null, new HitTestResultCallback(myCallback), new PointHitTestParameters(pt));
}

// If a child visual object is hit, toggle its opacity to visually indicate a hit.
public HitTestResultBehavior myCallback(HitTestResult result)
{
    if (result.VisualHit.GetType() == typeof(DrawingVisual))
    {
        if (((DrawingVisual)result.VisualHit).Opacity == 1.0)
        {
            ((DrawingVisual)result.VisualHit).Opacity = 0.4;
        }
        else
        {
            ((DrawingVisual)result.VisualHit).Opacity = 1.0;
        }
    }

    // Stop the hit test enumeration of objects in the visual tree.
    return HitTestResultBehavior.Stop;
}
' Capture the mouse event and hit test the coordinate point value against
' the child visual objects.
Private Sub MyVisualHost_MouseLeftButtonUp(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
    ' Retrieve the coordinates of the mouse button event.
    Dim pt As Point = e.GetPosition(CType(sender, UIElement))

    ' Initiate the hit test by setting up a hit test result callback method.
    VisualTreeHelper.HitTest(Me, Nothing, New HitTestResultCallback(AddressOf myCallback), New PointHitTestParameters(pt))
End Sub

' If a child visual object is hit, toggle its opacity to visually indicate a hit.
Public Function myCallback(ByVal result As HitTestResult) As HitTestResultBehavior
    If result.VisualHit.GetType() Is GetType(DrawingVisual) Then
        If (CType(result.VisualHit, DrawingVisual)).Opacity = 1.0 Then
            CType(result.VisualHit, DrawingVisual).Opacity = 0.4
        Else
            CType(result.VisualHit, DrawingVisual).Opacity = 1.0
        End If
    End If

    ' Stop the hit test enumeration of objects in the visual tree.
    Return HitTestResultBehavior.Stop
End Function

См. также