当前位置: 首页 > 工具软件 > Drawing > 使用案例 >

WPF_图画(二)Drawing抽象类

东和怡
2023-12-01

WPF_图画(一)Shape类及其派生类
WPF_图画(二)Drawing抽象类
WPF_图画(三)DrawingVisual类

Geometry抽象类表示形状或路径。Drawing抽象类扮演了互补的角色,它表示2D图画(Drawing)。

Drawing抽象类用于表示所有类型的2D图形,并且还有一小组类继承自该类:

说明属性
GeometryDrawing封装一个几何图形,该几何图形具有填充它的画刷和绘制其边框的画笔Geometry、Brush、Pen
ImageDrawing封装一副图像(通常是基于文件的位图图像),该图像具有定义图像边界的矩形ImageSource、Rect
VideoDrawing结合用于播放视频文件的媒体播放器和定义其边界的矩形Player、RectDr
Drawing组合各种类型的Drawing

因为继承自Drawing的类不是元素(没有继承UIElement类),所以不能将它们放置到用户界面中,所以还需要用于显示图画的类。

父类说明
DrawingImageImageSource允许在Image元素中驻留图画
DrawingBrushBrush允许使用画刷封装图画,之后就可以用画刷绘制任何表面
DrawingVisualVisual允许在低级的可视化对象中放置图画。可视化对象并不具有真正元素的开销,但是如果实现了需要的基础结构,那么仍可以显示可视化对象。

但是它们提供了使用更少系统资源显示2D内容的方法。可以减少元素数量。

DrawingImage示例

        <Button>
            <Image Stretch="Fill">
                <Image.Source>
                    <DrawingImage>
                        <DrawingImage.Drawing>
                            <GeometryDrawing Brush="Red">
                                <GeometryDrawing.Pen>
                                    <Pen Brush="Black" Thickness="0" />
                                </GeometryDrawing.Pen>
                                <GeometryDrawing.Geometry>
                                    <EllipseGeometry
                                        Center="50 50"
                                        RadiusX="10"
                                        RadiusY="5" />
                                </GeometryDrawing.Geometry>
                            </GeometryDrawing>
                        </DrawingImage.Drawing>
                    </DrawingImage>
                </Image.Source>
            </Image>
        </Button>

为了使用DrawingImage,所以在Button中添加了一个Image元素(Image元素是占资源的),然后在DrawingImage中封装了GeometryDrawing对象。

DrawingBrush示例

对于上面那个例子,还可以更加省资源,就是使用DrawingBrush。

        <Button>
            <Button.Background>
                <DrawingBrush Stretch="Fill" Viewport="0.1 0.1 0.8 0.8">
                    <DrawingBrush.Drawing>
                        <GeometryDrawing Brush="Red">
                            <GeometryDrawing.Pen>
                                <Pen Brush="Black" Thickness="0" />
                            </GeometryDrawing.Pen>
                            <GeometryDrawing.Geometry>
                                <EllipseGeometry
                            Center="50 50"
                            RadiusX="10"
                            RadiusY="5" />
                            </GeometryDrawing.Geometry>
                        </GeometryDrawing>
                    </DrawingBrush.Drawing>
                </DrawingBrush>
            </Button.Background>
        </Button>

注意,DrawingBrush中还有一个Viewport属性。

小结

  • 上述两个方法由于减少了元素的数量,因此降低了所需的开销,付出的代价是不能再为每一个不同的路径处理事件(虽然上面示例可能就一个椭圆,实际可能更复杂)。
  • 无论是在DrawingImage本身中使用图形,还是使用DrawingBrush封装图形,都应当考虑使用资源分解标记,如有需要可以重复使用资源,而不必复制整块标记。
  • 这种设计不适合需要渲染大量图形元素的绘图密集型应用程序,这些应用程序面临的不是图形复杂程度的问题,而纯粹是单独的图形元素数量的问题。即使使用量级更轻的Geometry对象代替Path元素,需要的开销也仍会较大的影响性能。这种情况需要使用低级的可视化层(Visual Layer)模型。

DrawingVisual

Visual类是抽象类,所以不能创建该类的实例。相反,需要使用继承自Visual类的某一个类,包括UIElement类(该类是WPF元素模型的根)、Viewport3DVisual类(显示3D)以及ContainerVisual类(包含其他可视化对象的基本容器)。但是最有用的派生类是DrawingVisual类,该类继承自ContainerVisual类,并增加了支持绘制向往放置到可视化对象中的图形内容的功能。

为使用DrawingVisual类绘制内容,需要调用DrawingVisual.RenderOpen()方法。该方法返回一个可用于定义可视化内容的DrawingContext对象。绘制完毕后,需要调用DrawingContext.Close方法。

            DrawingVisual visual = new DrawingVisual();
            DrawingContext dc = visual.RenderOpen();
            //perform drawing here
            Pen pen = new Pen(Brushes.Red, 3);
            dc.DrawLine(pen, new Point(0, 50), new Point(50, 0));
            dc.DrawLine(pen, new Point(50, 0), new Point(100, 50));
            dc.DrawLine(pen, new Point(0, 50), new Point(100, 50));
            dc.Close();

当调用DrawingContext方法时,没有实际绘制可视化对象----而只是定义了可视化外观。当调用Close()方法结束绘制时,完成的图画被存储在可视化对象中,并通过只读的DrawingVisual.Drawing属性提供这些图画。WPF会保存Drawing对象,从而当需要时可以重新绘制窗口。

使用可视化对象的方式:

  • 在元素中封装DrawingVisual对象,并对它执行命中检测(hit testing)。
  • 通过重写OnRender()方法,使可视化对象渲染自定义绘图元素。

在元素中封装可视化对象

为显示可视化对象,还需要借助于功能完备的WPF元素,WPF元素将可视化对象添加到可视化树中。单个元素具有显示任意数量可视化对象的能力,因此,可以很容易地创建只包含一两个元素,但驻留了几千个可视化对象的窗口。具体在这一篇中介绍:

为在元素中驻留可视化对象,需要执行以下任务:

  • 为元素调用AddVisualChild()和AddLogicalChild()方法来注册可视化对象。从技术角度看,为了显示可视化对象,不需要执行这些任务,但为了保证正确跟踪可视化对象、在可视化树和逻辑树中显示可视化对象以及使用其他WPF特性(如命中测试),需要执行这些操作。
  • 重写VisualChildrenCount属性并返回已经增加了的可视化对象的数量。
  • 重写GetVisualChild()方法,当通过索引号请求可视化对象时,添加返回可视化对象所需的代码。
 类似资料: