通过上一章的学习,Geometry抽象类表示形状或路径。Drawing抽象类扮演了互补的角色,它表示2D图画(Drawing)——换句话说,它包含了显示矢量图像或位图需要的所有信息。

  尽管有几类画图类,但只有GeometryDrawing类能使用已经学习过的几何图形。它增加了决定如何绘制图形的画笔和填充细节。可将GeometryDrawing对象视为矢量插图中的形状。例如,可将标准的窗口元文件格式(.wmf)转换成准备插入用户界面的GeometryDrawing对象的集合。

  分析一个简单的示例有帮助的。前面已经看到了如何定义表示三角形的PathGeometry对象:

<PathGeometry>
<PathFigure IsClosed="True" StartPoint="0,100">
<LineSegment Point="100,100"/>
<LineSegment Point="100,50"/>
</PathFigure>
</PathGeometry>

  可使用PathGeometry对象创建GeometryDrawing对象,如下所示:

<GeometryDrawing  Brush="Yellow" >
<GeometryDrawing.Pen>
<Pen Brush="Blue" Thickness="3"></Pen>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="10,100">
<LineSegment Point="100,100" />
<LineSegment Point="100,50" />
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>

  现在,PathGeometry对象定义了形状(三角形)。GeometryDrawing对象定义了形状的外观(具有蓝色边界的黄色三角形)。PathGeometry对象和GeometryDrawing对象都不是元素,所以不能直接使用这两个对象中的任何一个为窗口添加自己绘制的内容,而需要使用另一个支持图画的类。

  GeometryDrawing类不是WPF总唯一的图画类(尽管当使用2D矢量图形时,该类是最相关的一个类)。实际上,Drawing类用于表示所有类型的2D图形,并且还有一个小组类继承自该类。下表列出了所有这些类。

表 图画类

 一、显示图画

  因为继承自Drawing的类不是元素,所以不能将它们放置到用户界面中。为了显示图画,需要使用下表列出的三个类中的一个。

表 用于显示图画的类

  所有这些类中都存在通用主题。非常简单,它们提供了使用更少系统资源显示2D内容的方法。

  例如,假如希望使用矢量图像为按钮创建图表。最简单的方法(也是占用资源最多的方法)是在按钮中放置Canvas控件,并在Canvas控件中放置一系列继承自Shape类的元素:

<Button ...>
<Canvas ...>
<Polyline ...>
<Polyline ...>
<Rectangle ...>
<Ellipse ...>
<Polygon ...>
</Canvas>
</Button>

  现在已经知道,如果是使用这种方法,每个元素都是完全独立的,具有自己的内存区域和事件处理程序等。一个更好的减少元素数量的方法是Path元素。因为每个路径具有单独的笔画和填充,所以仍需要大量Path对象,不过这还是能够在一定程度上减少元素数量:

<Button ...>
<Canvas ...>
<Path ...>
<Path ...>
...
</Canvas>
</Button>

  一旦开始使用Path元素,就将独立形状变换为不同的几何图形。可从路径中提取几何图形、笔画以及填充信息并将它们转换成图画,从而再增加一个抽象层。然后可在DrawingGroup对象中将这些图画融合在一起,并将DrawingGroup对象放置到DrawingImage对象中,DrawingImage对象又可被放入到Image元素中。下面是这一过程创建的新标记:

<Button ...>
<Image ...>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing ...>
<GeometryDrawing ...>
<GeometryDrawing ...>
...
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Button>

  这是一次意义重大的改变。该例并没有简化标记,只是用GeometryDrawing对象代替了每个Path对象。然而,由于减少了元素的数量,因此降低了所需的开销。在前面的示例中创建了包含在按钮中的Canvas控件,并为每个路径添加了单独的元素。但该例只需要一个嵌套的元素:位于按钮中的Image元素。付出的代价是不能再为每个不同的路径处理事件(例如,不能探测鼠标在图画中独立区域的单击操作)。但在用于按钮的静态图像中,未必需要使用这种功能。

  尽管使用DrawingImage对象已经节省了大量资源,但仍可进一步提高效率,借助于Drawing删除另一个元素。

  基本思想是在DrawingBrush对象中的封装DrawingImage对象,如下所示:

<Button ...>
<Button.Background>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing ...>
<GeometryDrawing ...>
<GeometryDrawing ...>
<....>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Button.Background>
</Button>

  DrawingBrush方法和前面介绍的DrawingImage方法不完全相同。因为Image元素改变其内容的默认方式是不同的。Image.Stretch属性的默认值是Uniform,该设置会为了适应可用空间而放大或缩小图像。DrawingBrush.Stretch属性的默认值是Fill,该设置可能会扭曲图像。

  当改变DrawingBrush的Stretch属性时,为明确扭曲填充区域中图画的位置和尺寸,也可能希望调整Viewport设置。例如,下面的标记缩放由图画画刷使用的图画,以占用填充区域的90%:

<DrawinBrush Stretch="Fill" Viewport="0,0 0.9,0.9">

  对于按钮示例这是非常有用的。因为可为按钮周围的边框留出一定的空间。因为DrawingBrush并非元素,所以不能使用WPF布局过程。这意味着和Image元素不同,DrawingBrush中的内容放置不会考虑Button.Paddin属性值。

  使用DrawingBrush方式的一个古怪问题是,将鼠标移到按钮上时内容会消失,并且会使用一个新画刷绘制按钮表面。但当使用Image方式时,图片就不受影响。为了解决这个问题,需要为按钮创建自定义按钮控件模板,该模板使用不同的方式绘制按钮的背景。

  无论是在DrawingImage本身中使用图形,还是使用DrawingBrush封装图形,都应当考虑使用资源分解标记。基本思想是作为不同资源定义每个DrawingImage或DrawingBrush对象,从而当需要时就可以引用定义的对象。如果希望在多个元素或窗口中显示相同的内容,这是特别好的思想,因为只需要重用资源,而不必复制整块标记。如下面的示例所示:

<Window x:Class="Drawing.Drawings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Drawings" Height="300" Width="300">
<Window.Resources>
<GeometryDrawing x:Key="Drawing" Brush="Yellow" >
<GeometryDrawing.Pen>
<Pen Brush="Blue" Thickness="3"></Pen>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="10,100">
<LineSegment Point="100,100" />
<LineSegment Point="100,50" />
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</Window.Resources> <StackPanel Orientation="Horizontal" Margin="5">
<Button Width="30" Height="30">
<Image>
<Image.Source>
<DrawingImage Drawing="{StaticResource Drawing}">
</DrawingImage>
</Image.Source>
</Image>
</Button>
<Button Width="30" Height="30">
<Button.Background>
<DrawingBrush Stretch="Uniform" Viewport="0,0 0.9,1" Drawing="{StaticResource Drawing}">
</DrawingBrush>
</Button.Background>
</Button>
</StackPanel>
</Window>

Drawings

 二、导出插图

  尽管所有这些示例都内联地声明他们的图画,但更常用的方法是将该内容的某些部分放到资源字典中,从而可在整个应用程序中重用(并非一个地方进行修改)。由用户来确定如何将这些标记分割到资源中,但两种常用的方法是,存储一个充满DrawingImage对象的字典,或存储一个保存DrawingBrush对象的字典。此外,也可以分离出Geometry对象,并将它们存储为独立的资源。如上面的示例所示。

  当然,很少有开发人员会手动编写大量图形。反而, 他们将使用专门的设计工具导出所需的XAML内容。大多数设计工具目前还不支持XAML导出功能,不过有许多插件和转换工具可以弥补这一缺陷。下面是几个例子:

  •   http://www.mikeswanson.com/XAMLExport/上有一个用于Adobe Illustrator工具的免费XAML插件
  •   http://www.mikeswanson.com/swf2xaml/上有一个用于Adobe Flash文件的免费XAML转换工具。
  •   Expression Design是Microsoft公司的插入和图形设计程序,内置了XAML导出功能。该程序能够读取各种矢量图形文件格式,包括.wmf(Windows元文件格式)文件,还可以导入已经存在的插图并将其导出为XAML格式。

  然而,即使使用其中某个工具,前面学习的有关图形和图画的知识依然十分重要,主要原因如下几点:

  首先,许多程序允许选择是希望作为Canvas控件中的独立元素的组合导出图画,还是希望作为DrawingBrush或DrawingImage资源的集合导出图画。通常,第一种选择是默认选择,因为它保留了许多特性。然而,如果使用大量图画,并且图画很复杂,或者只是希望为了尽可能减少内存需求而使用静态图形,如按钮图形,使用DrawingBrush或DrawingImage资源更好的多。而且,这些格式和用户界面的其他部分是相互独立的,所以在以后很容易更新它们。

  之所以说理解2D图形基础知识是很重要的,另一个原因是这样可以更容易地控制它们。例如,可通过以下方式替换标准的2D图形:修改用于绘制各种形状的画刷、为单个几何图形应用变化、改变不透明度或者变换整个形状层(通过DrawingGroup对象)。更富有戏剧性的是,可添加、删除和替换单个几何图形。

【WPF学习】第四十四章 图画的更多相关文章

  1. 【WPF学习】第二十六章 Application类——应用程序的生命周期

    在WPF中,应用程序会经历简单的生命周期.在应用程序启动后,将立即创建应用程序对象,在应用程序运行时触发各种应用程序事件,你可以选择监视其中的某些事件.最后,当释放应用程序对象时,应用程序将结束. 一 ...

  2. 【WPF学习】第十四章 事件路由

    由上一章可知,WPF中的许多控件都是内容控件,而内容控件可包含任何类型以及大量的嵌套内容.例如,可构建包含图形的按钮,创建混合了文本和图片内容的标签,或者为了实现滚动或折叠的显示效果而在特定容器中放置 ...

  3. 【WPF学习】第二十四章 基于范围的控件

    WPF提供了三个使用范围概念的控件.这些控件使用在特定最小值和最大值之间的数值.这些控件——ScrollBar.ProgressBar以及Slider——都继承自RangeBase类(该类又继承自Co ...

  4. 【WPF学习】第二十九章 元素绑定——将元素绑定到一起

    数据banding的最简单情形是,源对象时WPF元素而且源属性是依赖性属性.前面章节解释过,依赖项属性具有内置的更改通知支持.因此,当在源对象中改变依赖项属性的值时,会立即更新目标对象中的绑定属性.这 ...

  5. 【WPF学习】第十五章 WPF事件

    前两章学习了WPF事件的工作原理,现在分析一下在代码中可以处理的各类事件.尽管每个元素都提供了许多事件,但最重要的事件通常包括以下5类: 生命周期事件:在元素被初始化.加载或卸载时发生这些事件. 鼠标 ...

  6. 【WPF学习】第二十二章 文本控件

    WPF提供了三个用于输入文本的控件:TextBox.RichTextBox和PasswordBox.PasswordBox控件直接继承自Control类.TextBox和RichTextBox控件间接 ...

  7. 【WPF学习】第十九章 控件类

    WPF窗口充满了各种元素,但这些元素中只有一部分是控件.在WPF领域,控件通常被描述为与用户交互的元素——能接收焦点并接受键盘或鼠标输入的元素.明显的例子包括文本框和按钮.然而,这个区别有时有些模糊. ...

  8. 【WPF学习】第二十五章 日期控件

    WPF包含两个日期控件:Calender和DatePicker.这两个控件都被设计为允许用户选择日期. Calendar控件显示日期,在与Windows操作系统中看到的日历(例如,当配置系统日期时看到 ...

  9. 我的MYSQL学习心得(十四) 备份和恢复

    我的MYSQL学习心得(十四) 备份和恢复 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) ...

  10. “全栈2019”Java第四十九章:重载与重写对比详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

随机推荐

  1. Go Web 编程之 请求

    概述 前面我们学习了处理器和处理器函数,如何编写和注册处理器.本文我们将学习如何从请求中获取信息. 请求的结构 通过前面的学习,我们知道处理器函数需要符合下面的签名: func (w http.Res ...

  2. 全流程开发 TP6.0实战高并发电商服务系统*完

    在TP6框架中我们可以学到TP整体知识,如下图一所示: 图一:TP6整体知识点 这些内容都会在实战课程中一一涵盖,并且在课程中我们会用到五层架构思想(如图二),和传统的MVC架构有所不一样,这样做可以 ...

  3. TensorFlow——训练模型的保存和载入的方法介绍

    我们在训练好模型的时候,通常是要将模型进行保存的,以便于下次能够直接的将训练好的模型进行载入. 1.保存模型 首先需要建立一个saver,然后在session中通过saver的save即可将模型保存起 ...

  4. 第7节class与style绑定

    方法一 效果图:  方法二 效果图:  方法三 效果图: 代码: <!DOCTYPE html> <html lang="en" xmlns:v-bind=&qu ...

  5. cogs 495. 滑动窗口 单调队列

    495. 滑动窗口 ★★   输入文件:window.in   输出文件:window.out   简单对比时间限制:2 s   内存限制:256 MB [问题描述] 给你一个长度为N的数组,一个长为 ...

  6. git与github的简单使用教程

    git与github的简单使用教程 一.创建仓库 点击new,进入创建仓库页面 对将要创建的仓库进行一些简单的设置 最后再点击create repository就可以了. 到这我们就创建好了一个仓库. ...

  7. TCP/IP协议与HTTP协议(二)

    TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据. 1.TCP连接 手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过 ...

  8. 前端笔记5-js1

    一.在JS中一共有6种数据类型1. String 字符串2. Number 数值3. Boolean 布尔值4. Null 空值5. Undefined 未定义6. Object 对象 其中 Stri ...

  9. Nginx. 用http访问https跨域

    用http 访问 https域名, 报跨越问题 解决方法: 在nginx相应服务的转发配置下添加: add_header 'Access-Control-Allow-Origin' 'http://i ...

  10. 异数OS-星星之火(二)--远程实验室注册开放

    异数OS-星星之火(二) 远程实验室注册开放 异数os-织梦师云 未来操作系统技术远程实验室预计9月中旬开放,提供异数os用户学习研究测试服务,目前在做容器化多租户环境改造,先开放会员预注册通道,有需 ...