使用 DrawingVisual 对象
本主题概述如何在 WPF 可视化层中使用 DrawingVisual 对象。
DrawingVisual 对象
DrawingVisual 是一个轻量绘图类,用于呈现形状、图像或文本。 此类之所以为轻量类是因为它不提供布局或事件处理,从而性能得以提升。 因此,绘图非常适用于背景和剪贴画。
DrawingVisual 宿主容器
为了使用 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
注意
有关从中提取上述代码示例的完整代码示例,请参阅使用 DrawingVisual 的命中测试示例。
创建 DrawingVisual 对象
创建 DrawingVisual 对象时,该对象没有绘图内容。 可以通过检索对象的 DrawingContext 并在其中进行绘制来添加文本、图形或图像内容。 通过调用 DrawingVisual 对象的 RenderOpen 方法返回 DrawingContext。
要在 DrawingContext 中绘制一个矩形,请使用 DrawingContext 对象的 DrawRectangle 方法。 对于绘制其他类型的内容,存在类似的方法。 完成将内容绘制到 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