Usar objetos DrawingVisual
Este tema proporciona una introducción a cómo usar objetos DrawingVisual en la capa de objeto visual de WPF.
Objeto DrawingVisual
DrawingVisual es una clase de dibujo ligera que se utiliza para representar formas, imágenes o texto. Esta clase se considera ligera porque no proporciona control de diseño ni evento, lo que mejora su rendimiento. Por esta razón, los dibujos son ideales para fondos e imágenes prediseñadas.
Contenedor host de objetos DrawingVisual
Para usar objetos DrawingVisual, debe crear un contenedor host para ellos. El contenedor host debe derivar de la clase FrameworkElement, que proporciona la asistencia de control de diseño y evento que le falta a la clase DrawingVisual. El objeto contenedor host no muestra ninguna propiedad visible, puesto que su finalidad principal es contener objetos secundarios. Pero, la propiedad Visibility del contenedor host debe establecerse en Visible, si no, ninguno de los elementos secundarios será visible.
Cuando se crea un objeto contenedor host para objetos visuales, debe almacenar las referencias a los objetos visuales en un objeto VisualCollection. Use el método Add para añadir un objeto visual al contenedor host. En el ejemplo siguiente, se crea un objeto contenedor host y se agregan tres objetos visuales a su 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:
Para obtener el código completo del que se ha extraído el ejemplo de código anterior, vea Ejemplo Hit Test Using DrawingVisuals.
Crear objetos DrawingVisual
Cuando crea un objeto DrawingVisual, no tiene ningún contenido de dibujo. Puede agregar contenidos de texto, gráfico o imagen; para ello, recupere el objeto DrawingContext y dibuje en él. DrawingContext se devuelve llamando al método RenderOpen de un objeto DrawingVisual.
Para dibujar un rectángulo en DrawingContext, use el método DrawRectangle del objeto DrawingContext. Existen métodos similares para dibujar otros tipos de contenido. Cuando haya terminado de dibujar contenido en DrawingContext, llame al método Close para cerrar DrawingContext y conservar el contenido.
En el ejemplo siguiente, se crea un objeto DrawingVisual, y se dibuja un rectángulo en su 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
Crear invalidaciones para los miembros FrameworkElement
El objeto contenedor host es responsable de administrar su colección de objetos visuales. Para ello, el contenedor host debe implementar invalidaciones de miembros para la clase derivada FrameworkElement.
En la lista siguiente se describen los dos miembros que debe invalidar:
GetVisualChild: devuelve un elemento secundario en el índice especificado de una colección de elementos secundarios.
VisualChildrenCount: obtiene el número de elementos secundarios visuales de este elemento.
En el ejemplo siguiente, se implementan invalidaciones para los dos miembros de 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
Proporcionar compatibilidad con las pruebas de posicionamiento
El objeto contenedor host puede proporcionar control de eventos aunque no muestre ninguna propiedad visible. Pero, su propiedad Visibility debe establecerse en Visible. Esto permite crear una rutina de control de eventos para el contenedor host que pueda interceptar los eventos del mouse, tales como soltar el botón izquierdo. La rutina de control de eventos puede entonces implementar pruebas de posicionamiento al invocar el método HitTest. El parámetro HitTestResultCallback del método hace referencia a un procedimiento definido por el usuario que puede usar para determinar la acción resultante de una prueba de posicionamiento.
En el ejemplo siguiente, se implementa la compatibilidad con las pruebas de posicionamiento para el objeto contenedor host y sus elementos secundarios.
// 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
Vea también
.NET Desktop feedback