Usando objetos DrawingVisual

Este tópico fornece uma visão geral de como usar DrawingVisual objetos na camada visual do WPF.

Objeto DrawingVisual

O DrawingVisual é uma classe de desenho leve usada para renderizar formas, imagens ou texto. Essa classe é considerada leve porque não fornece layout ou manipulação de eventos, o que melhora o desempenho. Por esse motivo, desenhos são ideais para telas de fundo e clip-art.

Contêiner de host do DrawingVisual

Para usar DrawingVisual objetos, você precisa criar um contêiner de host para os objetos. O objeto de contêiner do host deve derivar FrameworkElement da classe, que fornece o suporte de layout e manipulação de eventos que a DrawingVisual classe não possui. O objeto do contêiner de host não exibe nenhuma propriedade visível, já que sua função principal é conter objetos filho. No entanto, a Visibility propriedade do contêiner do host deve ser definida como Visible; caso contrário, nenhum de seus elementos filho ficará visível.

Ao criar um objeto de contêiner de host para objetos visuais, você precisa armazenar as referências de objeto visual em um VisualCollectionarquivo . Use o Add método para adicionar um objeto visual ao contêiner do host. No exemplo a seguir, um objeto de contêiner de host é criado e três objetos visuais são adicionados ao seu 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

Observação

Para o exemplo de código completo do qual o exemplo de código anterior foi extraído, consulte Exemplo de teste de clique usando DrawingVisuals.

Criando objetos DrawingVisual

Quando você cria um DrawingVisual objeto, ele não tem conteúdo de desenho. Você pode adicionar texto, elementos gráficos ou conteúdo de imagem recuperando o do objeto DrawingContext e desenhando nele. A DrawingContext é retornado chamando o RenderOpen método de um DrawingVisual objeto.

Para desenhar um retângulo no DrawingContext, use o DrawRectangle método do DrawingContext objeto. Existem métodos semelhantes para desenhar outros tipos de conteúdo. Quando terminar de desenhar o conteúdo no , chame o método para fechar o e persistir o DrawingContextCloseDrawingContext conteúdo.

No exemplo a seguir, um objeto é criado e um DrawingVisual retângulo é desenhado em seu 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

Criando substituições para membros FrameworkElement

O objeto do contêiner de host é responsável por gerenciar sua coleção de objetos visuais. Isso requer que o contêiner do host implemente substituições de membro para a classe derivada FrameworkElement .

A lista a seguir descreve os dois membros que você deve substituir:

  • GetVisualChild: Retorna um filho no índice especificado da coleção de elementos filho.

  • VisualChildrenCount: Obtém o número de elementos filho visuais dentro desse elemento.

No exemplo a seguir, substituições para os dois FrameworkElement membros são implementadas.


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

Fornecendo suporte a teste de clique

O objeto de contêiner do host pode fornecer manipulação de eventos mesmo que não exiba nenhuma propriedade visível — no entanto, sua Visibility propriedade deve ser definida como Visible. Isso permite que você crie uma rotina de manipulação de evento para o contêiner de host que pode capturar eventos de mouse, como a liberação do botão esquerdo do mouse. A rotina de manipulação de eventos pode então implementar o teste de ocorrências invocando o HitTest método. O parâmetro do HitTestResultCallback método refere-se a um procedimento definido pelo usuário que você pode usar para determinar a ação resultante de um teste de acerto.

No exemplo a seguir, o suporte para teste de clique é implementado para o objeto do contêiner de host e seus filhos.

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

Confira também