Condividi tramite


Utilizzo di oggetti DrawingVisual

In questo argomento viene fornita una panoramica di come usare gli oggetti DrawingVisual nel livello visivo WPF.

Oggetto DrawingVisual

Il DrawingVisual è una classe di disegno leggera usata per eseguire il rendering di forme, immagini o testo. Questa classe è considerata leggera perché non fornisce layout o gestione degli eventi, migliorandone le prestazioni. Per questo motivo, i disegni sono ideali per sfondi e clipart.

Contenitore per DrawingVisual

Per usare gli oggetti DrawingVisual, è necessario creare un contenitore host per gli oggetti . L'oggetto contenitore host deve derivare dalla classe FrameworkElement, che fornisce il supporto per il layout e la gestione degli eventi mancanti nella classe DrawingVisual. L'oggetto contenitore host non visualizza alcuna proprietà osservabile, poiché il suo scopo principale è contenere oggetti figlio. Tuttavia, la proprietà Visibility del contenitore host deve essere impostata su Visible; in caso contrario, nessuno dei relativi elementi figlio sarà visibile.

Quando si crea un oggetto contenitore host per gli oggetti visivi, è necessario archiviare i riferimenti all'oggetto visivo in un VisualCollection. Usare il metodo Add per aggiungere un oggetto visivo al contenitore host. Nell'esempio seguente viene creato un oggetto contenitore host e tre oggetti visivi vengono aggiunti al relativo 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

Nota

Per l'esempio di codice completo da cui è stato estratto l'esempio di codice precedente, vedere Hit Test using DrawingVisuals Sample.

Creazione di oggetti DrawingVisual

Quando si crea un oggetto DrawingVisual, non ha contenuto di disegno. È possibile aggiungere contenuto di testo, grafica o immagine recuperando il DrawingContext dell'oggetto e disegnandolo. Un DrawingContext viene restituito chiamando il metodo RenderOpen di un oggetto DrawingVisual.

Per disegnare un rettangolo nella DrawingContext, utilizzare il metodo DrawRectangle dell'oggetto DrawingContext. Esistono metodi simili per disegnare altri tipi di contenuto. Al termine del disegno nel DrawingContext, chiamare il metodo Close per chiudere il DrawingContext e rendere persistente il contenuto.

Nell'esempio seguente viene creato un oggetto DrawingVisual e viene disegnato un rettangolo nel relativo 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

Creazione di override per i membri di FrameworkElement

L'oggetto contenitore host è responsabile della gestione della raccolta di oggetti visivi. Ciò richiede che il contenitore host esegua le sovrascrizioni dei membri per la classe FrameworkElement derivata.

L'elenco seguente descrive i due membri di cui è necessario eseguire l'override:

  • GetVisualChild: restituisce un elemento figlio in corrispondenza dell'indice specificato dalla raccolta di elementi figlio.

  • VisualChildrenCount: Ottiene il numero di elementi figli visivi all'interno di questo elemento.

Nell'esempio seguente vengono implementate le sostituzioni per i due membri 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

Fornire supporto per il test di collisione

L'oggetto contenitore host può fornire la gestione degli eventi anche se non visualizza alcuna proprietà visibile, ma la relativa proprietà Visibility deve essere impostata su Visible. In questo modo è possibile creare una routine di gestione degli eventi per il contenitore host in grado di intercettare gli eventi del mouse, ad esempio il rilascio del pulsante sinistro del mouse. La routine di gestione degli eventi può quindi implementare hit testing richiamando il metodo HitTest. Il parametro HitTestResultCallback del metodo fa riferimento a una procedura definita dall'utente che è possibile usare per determinare l'azione risultante di un hit test.

Nell'esempio seguente viene implementato il supporto di hit testing per l'oggetto contenitore host e i relativi elementi figlio.

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

Vedere anche