本主题概述如何在 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