详细说明
示例性操作环境
图1示出了在其上可实现本发明的合适的计算系统环境100的示例。计算系统环境100只是合适的计算环境的一个示例,而非旨在建议任何对本发明的使用或功能范围的限制。计算环境100既不应解释为具有对示例性操作环境100中所示的组件的任意之一或组合的任何依赖性和要求。
本发明可用于众多其它通用或专用计算系统环境或配置。可适合于本发明使用的众所周知的计算系统、环境和/或配置的示例包括,但不限于,个人计算机、服务器计算机、手持或膝上型设备、写字板设备、多处理器系统、基于微处理机系统、机顶盒、可编程消费电子产品、网络PC、小型计算机、大型计算机、包括任何上述系统或设备的分布式计算环境等。
本发明可在由计算机执行的计算机可执行指令如程序模块的一般环境中描述。通常,程序模块包括例程、程序、对象、组件、数据结构等,它们完成特定任务或实现特定抽象数据类型。本发明还可在分布式计算环境中实施,其中任务可由通过通信网络连接的远程处理设备完成。在分布式计算环境中,程序模块可位于本地或远程两者的计算机存储介质中,包括存储器存储设备。
参考图1,实现本发明的示例性系统包括计算机110形式中的通用计算设备。计算机110的组件可包括,但不限于,处理单元120、系统存储器130和连接包括系统存储器在内的各种系统组件到处理单元120的系统总线121。系统总线121可以是任何若干类型的总线结构,包括存储器总线或存储器控制器、外围设备总线和使用任意各种总线结构的局部总线。作为示例,而非限制,这种结构包括工业标准结构(ISA)总线、微通道结构(MCA)总线、增强ISA(EISA)总线、视频电子标准协会(VESA)局部总线、加速图形接口(AGP)总线和也称为Mezzanine总线的外围组件互连(PCI)总线。
计算机110一般包括各种计算机可读介质。计算机可读介质可以是任何可由计算机110存取的可用介质,并包括易失性和非易失性、可移动和不可移动的介质。作为示例而非限制,计算机可读介质可包括计算机存储介质和通信介质。计算机存储介质包括以任何用于存储诸如计算机可读指令、数据结构、程序模块或其它数据的信息的方法或技术实现的易失性和非易失性、可移动和不可移动的介质。计算机存储介质包括,但不限于,RAM、ROM、EEPROM、闪存或其它存储器技术、CD-ROM、数字多功能盘(DVD)或其它光盘存储器、磁带盒、磁带、磁盘存储器或其它磁存储设备,或者任何可用来存储所想要的信息并能由计算机110存取的其它介质。通信介质一般包含在诸如载波或其它传输机制的调制数据信号中的计算机可读指令、数据结构、程序模块或其它数据,并包括任意信息传输介质。术语“调制数据信号”意指使得以编码信号中信息的方法设置或改变其一个或多个特征的信号。作为示例,但非限制,通信介质包括有线介质,诸如有线网络或直接线连接,和无线介质,诸如声波、RF、红外线和其它无线介质。上述任意的组合也应包括在计算机可读介质的范围内。
系统存储器130包括易失性和/或非易失性存储器形式的计算机存储介质,诸如只读存储器(ROM)131和随机存取存储器(RAM)132。基本输入/输出系统133(BIOS),包含帮助在计算机110内的元件间传送信息的基本例程,诸如在起动期间,一般存储在ROM 131中。RAM 132一般包含由处理单元120可立即访问和/或现在正操作的数据和/或程序模块。作为示例,而非限制,图1示出操作系统134、应用程序135、其它程序模块136和程序数据137。
计算机110还可包括其它可移动/不可移动、易失性/非易失性计算机存储介质。仅作为示例,图1示出读写不可移动、非易失性的磁介质的硬盘驱动器141、读写可移动、非易失性的磁盘152的磁盘驱动器151和读写诸如CD ROM或其它光介质的可移动、非易失性的光盘156的光盘驱动器155。其它可用于示例性操作环境的可移动/不可移动、易失性/非易失性计算机存储介质包括,但不限于,磁带盒、闪存卡、数字多功能盘、数字视频带、固态RAM、固态ROM等。硬盘驱动器141一般通过诸如接口140的不可移动存储接口连接到系统总线121,而磁盘驱动器151和光盘驱动器155一般由诸如接口150的可移动存储器接口连接到系统总线121。
以上讨论并示于图1的驱动器及其相关的计算机存储介质为计算机110提供了计算机可读指令、数据结构、程序模块和其它数据的存储。在图1中,例如,硬盘驱动器141被示为存储操作系统144、应用程序145、其它程序模块146和程序数据147。注意这些组件可以相同也可以不同于操作系统134、应用程序135、其它程序模块136和程序数据137。操作系统144、应用程序145、其它程序模块146和程序数据147在这里给出不同数字以至少示出它们是不同的拷贝。用户可通过诸如写字板(电子数字化转换器)164、话筒163、键盘162和通常称为鼠标、轨迹球或触摸板的指点设备161的输入设备将命令和信息输入到计算机110中。其它输入设备(未示出)可包括游戏操纵杆、游戏垫、卫星天线、扫描仪等。这些和其它输入设备常常通过耦合到系统总线的用户输入接口160连接到处理单元120上,但也可通过其它接口和总线结构连接,诸如并行端口、游戏端口或通用串行总线(USB)来连接。监视器191或其它类型的显示设备也通过诸如视频接口190的接口连接到系统总线121上。监视器191还可与触摸屏面板193等集成在一起,能够通过诸如触摸屏接口192的接口输入诸如手写内容的数字化输入到计算机系统110中。注意监视器和/或触摸屏面板可物理地耦合在其中结合了计算设备110的机架上,诸如写字板类型的个人计算机,其中触摸屏面板193实质上用作写字板164。另外,诸如计算设备110的计算机还可包括其它外围输出设备,诸如扬声器195和打印机196,它们可通过输出外围设备接口194等连接。
计算机110可运行在使用逻辑连接到一或多台诸如远程计算机180的远程计算机上的网络化环境中。远程计算机180可以是个人计算机、服务器、路由器、网络PC、对等设备或其它普通网络节点,且一般包括许多或所有上面相对于计算机110所述的元件,尽管只有存储器存储设备181示于图1。绘于图1的逻辑连接包括局域网(LAN)171和广域网(WAN)173,但还可包括其它网络。这样的网络化环境在办公室、企业级计算机网络、内联网和因特网中都很普通。
当在LAN网络环境中使用时,计算机110通过网络接口或适配器170连接到LAN171上。当在WAN网络环境中使用时,计算机110一般包括调制解调器172或其它在诸如因特网的WAN173上建立通信的设备。调制解调器172,它可以是内置或外置的,可通过用户输入接口160或其它合适的机制连接到系统总线121上。在网络化环境中,相关于计算机110所述的程序模块或其部分可存储在远程存储器设备中。作为示例,而非限制,图1示出了远程应用程序185,驻留在存储器设备181上。要意识到所示网络连接都是示例性的,并可使用其它在计算机间建立通信连接的装置。
示例性操作环境
图形体系结构
本发明的一个方面一般针对允许程序代码如应用程序或操作系统组件传送绘制指令和其它信息(例如图像位图)到图形组件,以便在系统显示器上呈现图形输出。为此,本发明提供一种标记语言,连同一组形状元素和其它元素,并且与对象模型中的普通属性系统集成以使程序能够用数据结构、绘图元(命令)和其它图形相关的数据来填充场景图。当处理时,场景图产生在屏幕上显示的图形。
图2表示一般的分层的体系结构200,在其中可实现本发明。如在图2中所示,可开发程序代码202(例如,应用程序或操作系统组件等),以一种或多种不同方法输出图形数据,包括通过成像204、通过向量图形元素206和/或通过直接放置到视件应用编程接口(API)层212的函数/方法调用。与API层的直接交互还在题为“Visual and Scene Graph Interface(视件和场景图接口)”的上述共同待批的专利申请中描述。
通常,成像201为程序代码202提供一种机制,用于加载、编辑和保存图像,例如位图。这些图像可由系统的其它部件使用,并且还存在一种使用图元绘制代码直接绘制图像的方法。
按照本发明的一个方面,向量图形元素206提供另一种方法绘制图形,与对象模型(下面描述)的其余部分相一致。可通过标记语言创建向量图形元素206,元素/属性系统208和布局系统210处理向量图形元素206以产生对视件API层212的适当调用。如下所述,通常将向量图形元素206分析成对象模型的对象,从它们绘制场景图,可通过元素层通过元素/属性系统208和布局系统210来提供,或者可在资源层以更有效方式来提供,也如下所述。
在一个实现中,图形层体系结构200包括高层合成和动画引擎214,该引擎包括或者与高速缓存数据结构216相关联。高速缓存数据结构216包含场景图,该图包括按照已定义的对象模型管理的分层安排的各对象,如下所述。通常,视件API层212为程序代码202(和布局系统210)提供接口到高速缓存数据结构216,包括创建对象、打开和和关闭对象以给它们提供数据等等。换言之,高层合成和动画引擎214揭示统一的媒体API层212,通过它开发者可表达关于图形和媒体的意图以显示图形信息,并且为基础平台提供足够的信息,使得该平台能为程序代码优化对于硬件的使用。例如,基础平台将负责高速缓存、资源协商和媒体集成。
在一个实现中,高层合成和动画引擎214传递指令流及可能的其它数据(例如,位图的指针)到快速的低层合成和动画引擎218。如在此使用的术语“高层(high-level)”和“低层(low-level)”与在其它计算情景中使用的相似,其中通常,软件组件相对于较高组件越低,该组件就离硬件越近。因而,例如,从高层合成和动画引擎214发送图形信息可在低层合成和动画引擎218处接收,在这里使用该信息发送图形数据到包括硬件222在内的图形子系统。
高层合成和动画引擎214和程序代码202一起构建场景图,它表示由程序代码202提供的图形场景。例如,可用绘制指令加载要绘制的每个项目,系统可以将绘制指令高速缓存在场景图数据结构216中。如将在下面描述的,有许多不同方法指定这个数据结构216和要绘制的内容。而且,高层合成和动画引擎214与定时和动画系统220集成以提供说明性(或其它)动画控制(例如动画时间间隔)和定时控制。注意,动画系统允许动画值实质上被传递到系统中的任何地方,包括例如,在元素属性层208处,在视件API层202内,和在任何其它资源中。定时系统在元素和视件层揭示。
低层合成和动画引擎218管理场景的合成、动画和呈现,场景然后被提供给图形子系统222。低层引擎218合成多个应用的场景,并且通过呈现组件,实现图形到屏幕的实际呈现。然而,注意,有时候在较高层发生某种呈现可能是必需和有益的。例如,在较低层为来自多个应用的请求服务的同时,较高层在每应用基础上实例化,因此,有可能通过成像机制204在较高层执行耗时或应用-专用的呈现,并且将对位图的引用传递给较低层。
场景图对象模型
如下所述,较高层基于控件的向量图形元素206与由在场景图数据结构216中使用的视件API层212创建的较低层对象共享呈现模型。这在本发明的较高层元素与较低层元素之间提供大量相关性。下面描述场景图对象模型的一种实现。
本发明提供若干访问图形和呈现服务的层。在顶层,向量图形提供许多对于基于XML的图形标记共同的优点,包括与本发明的对象模型一起使用简单,易于重用,并且一般为相似系统的用户所熟悉。对象可作为标记元素使用,连同或者作为那些元素上的属性或者作为复杂属性揭示的属性。
本发明通过Visual(视件)对象的使用呈现图形内容。这个基础Visual层可用若干方法使用。编程者可以直接以代码访问视件;他们可以使用对象模型编程;并且,按照本发明一个方面,他们可以使用基于XML的标记。
预定义的向量形状可在向量图形中使用,如Polygon(多边形)和Path(路径)元素,并且包含在一个布局元素内,如在Canvas(画布)、Dock Panel(停放面板)和Flow Panel(流动面板)内。Canvas元素提供一种将元素绝对地定位在双亲空间内的方法。对于Canvas及其子形状,测量屏幕坐标的默认单位是与设备无关的像素。DockPanel和FlowPanel提供许多尺寸和对齐属性,以及在边界上的控制。
向量图形提供许多已定义的向量图形形状,将为SVG的用户所熟悉。这些元素从Shape(形状)类继承,并且包括Ellipse(椭圆)、Line(直线)、Path(路径)、Polygon(多边形)、Polyline(折线)和Rectangle(矩形)。这些元素从Shape继承了许多共同的属性,包括Stroke(笔划)和StrokeThickness(笔划粗细)、Fill(填充),以及指定坐标和顶点的数据属性。开发者也可以通过应用变换来偏斜、旋转、平移和缩放形状。
Line元素提供一个适宜的例子。下面的例子指定起点和终点的坐标,笔划颜色和宽度,以及在线端的圆形帽盖。
<Canvas ID=″root″
xmlns=″http://schemas.microsoft.com/2003/xaml″
Background=″White″>
<Line Stroke=″#000000″
StrokeThickness=″10″
StrokeStartLineCap=″2″
StrokeEndLineCap=″2″
X1=″200″
Y1=″10″
X2=″50″
Y2=″300″/>
</Canvas>
Ellipse是通过用CenterX(中心X轴坐标)和CenterY(中心Y轴坐标)属性定义形状的中心来创建的。代替指定焦点,椭圆的边界是通过设置RadiusX(X轴半径)和RadiusY(Y轴半径)属性来设置的。为在向量图形中绘制圆,开发者可以指定一个椭圆,其RadiusX和RadiusY值相等。
<Ellipse
Fill=″yellow″
CenterX=″3in″
CenterY=″2.2in″
RadiusX=″1in″
RadiusY=″2in″
FillOpacity=″0.3″
StrokeWidth=″4px″
Stroke=″blue″/>
Path对象提供绘制曲线和复杂形状(无论是开放的还是闭合的)的方法。Path不仅揭示一般在从Shape类继承的对象上可使用的属性,而且还使开发者能够指定更多描述曲线的复杂参数。开发者可以用标记以各种方法使用路径,包括使用在Data(数据)中的特殊句法来指定路径数据,或者使用PathGeometry(路径几何形状)和PathGeometry对象来指定各个路径段。
为Data属性提供的坐标对和内联参数可以指定直线段、贝塞尔曲线以及各种各样其它路径规范。下面的例子示出定义两个子路径的Path元素。
<Canvas ID=″root″
xmlns=″http://schemas.microsoft.com/2003/xaml″
Background=″White″>
<Path Data=″M100,200 C 100,25 400,350 400,175H
280″
Stroke=″DarkGoldenRod″
StrokeThickness=″3″/>s
</Canvas
Data属性串从“移动到(moveto)”命令开始,由M表示,它为该路径在Canvas的坐标系统中建立一个起点。Path数据参数是区分大小的。大写字母M表示新的当前点的绝对位置。小写字母m表示相对坐标。第一个子路径是三次贝塞尔曲线,始于(100,200)并终于(400,175),使用两个控制点(100,25)和(400,350)来绘制。这个子路径由Data属性串中的C命令表示。再次,大写字母C表示绝对路径;小写字母c表示相对路径。
第二个子路径以绝对水平的“直线到(lineto)”命令H开始,它指定从先前子路径的终点(400,175)到新的终点(280,175)绘制的直线。因为它是一个水平的“直线到”命令,所以指定的值是x轴坐标。
有可能在标记中使用更冗长的句法来指定路径数据,这具有允许开发者指定复杂属性和使标记更可读的优点。在这种情况下,PathGeometry对象可用于创建复杂形状,如弧和曲线。PathGeometry对象由一或多个PathFigure(路径外形)对象组成;每个PathFigure表示不同的“外形”或形状。每个PathFigure本身由一或多个PathSegment(路径段)组成,每个表示该外形或形状的一个连接的部分。Segment类型包括LineSegment(直线段)、BezierSegment(贝塞尔段)和ArcSegment(弧段)。
下面的代码通过使用PathGeometry和PathFigure指定路径数据;添加若干段到PathFigure以形成形状。在这种情况下,已经使用PathFigure对象的Segment属性添加了段。这个标记创建四个贝塞尔曲线。注意,PathFigure的第一个段是StartSegment(起始段):
<Canvas ID=″root″
Background=″White″
xmlns=″http://schemas.microsoft.Com/2003/xaml″>
<Path ID=″myPath″
Fill=″Blue″
Stroke=″Black″
StrokeThickness=″5″>
<Path.Data>
<GeometryCollection>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure>
<PathFigure.Segments>
<PathSegmentCollection>
<StartSegment Point=″400,100″/>
<BezierSegment Point1=″400,100″
Point2=″400,200″Point3=″200,300″/>
<BezierSegment Point1=″400,100″
Point2=″400,100″Point3=″200,50″/>
<BezierSegment Point1=″0,100″
Point2=″0,200″Point3=″200,300″/>
<BezierSegment Point1=″0,300″
Point2=″0,100″Point3=″200,50″/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</GeometryCollection>
</Path.Data>
</Path>
</Canvas>
向量图形形状揭示了Brush(画刷)的各种属性来指定它们的Stroke和Fill的颜色。下面的例子指定在Canvas和Ellipse元素上的这些属性。注意,颜色属性的有效输入可以是关键字或十六进制颜色值。
<Canvas ID=″root″
xmlns=″http://schemas.microsoft.com/2003/xaml″
Background=″LightGray″
<Ellipse
Fill=″#FFFFFF00″
CenterX=″100″
CenterY=″200″
RadiusX=″75″
RadiusY=″75″
StrokeThickness=″5″
Stroke=″#FF0000FF″/>
</Canvas>
可供替换地,开发者可以使用复杂属性句法和SolidColorBrush(纯色画刷)类来指定颜色。使用复杂句法指定属性在通过属性页重用图形标记时或者在动画形状属性如颜色时变得有必要。
<Canvas ID=″root″
xmlns=″http://schemas.microsoft.com/2003/xaml″
Background=″LightGray″>
这个不规则的折线形状使用Stroke和Fill属性的预定义颜色值。在这种情况下,通过使它稍微地透明(不透明性为0.8),FillOpacity(填充不透明性)属性影响填充颜色,因此它与任何基础颜色混合:
<Polyline
Points=″300,200400,125400,275 300,200″
Stroke=″Purple″
StrokeThickness=″2.3″>
<Polyline.Fill>
<SolidColorBrush Color=″Blue″Opacity=″0.4″/>
</Polyline.Fill>
</Polyline></Canvas>
只有在指定形状的纯色填充和背景时,才可指定渐变。下面的例子设置水平渐变作为Rectangle的Fill属性,其中Blue(蓝)作为起始颜色而Red(红)作为结束颜色。
<Rectangle
Fill=″HorizontalGradient Blue Red″
RectangleLeft=″120″
RectangleTop=″120″
RectangleWidth=″100″
RectangleHeight=″100″>
</Rectangle>
开发者也可以用复杂属性符号来指定渐变。这个符号在呈现渐变时提供较大程度的特异性,并且揭示附加的属性。例如,为用渐变动画形状的填充,使用复杂符号。下面的例子使用RadialGradientBrush(径向渐变画刷)对象设置Rectangle上的渐变。RadialGradientBrush对象提供对渐变对象属性的访问,如它的半径和可能在其上设置的任何变形或动画;这些属性是从GradientBrush(渐变画刷)继承的。GradientStopCollection(渐变停止符集合)集合使开发者能够指定多个渐变停止符并且指示了它们的Offset(偏移)(在渐变中停止符的位置):
<Rectangle RectangleLeft=″10″RectangleTop=″250″
RectangleWidth=″300″RectangleHeight=″200″>
<Rectangle.Fill>
<RadialGradientBrush Focus=”0.5,0.5”>
<RadialGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color=″red″Offset=″0″/>
<GradientStop Color=″yellow″Offset=″1″/>
<GradientStop Color=″blue″Offset=″0.5″1/>
</GradientStopCollection>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
本发明提供向量绘制形状的标准变形。开发者可以偏斜形状、旋转它们、改变它们的尺度,以及平移(改变位置)它们,或者作为静态图形或者在动画中。为在标记中使用Transform(变形)对象,它们需要被指定为TransformDecorator(变形装饰者)的子对象。
ScaleTransform()变换是最简单的可用变换,并且通过简单地指定应当改变元素尺寸的系数来使用它。下面的例子沿双亲Canvas的坐标系统的y-轴按150%重新改变Polygon元素尺寸。
<Canvas ID=″root″
xmlns=″http://schemas.micrsoft.com/2003/xaml″>
<TransformDecorator AffectsLayout=″false″>
<TransformDecorator.Transform>
<ScaleTransform ScaleX=″1″ScaleY=″1.5″/>
</TransformDecorator.Transform>
<Polygon ID=″star3″
Stroke=″red″
StrokeThickness=″2.0″
Points=″176.5,50 189.2,155.003 286.485,113.5
201.9,177286.485,240.5
189.2,198.997176.5,304163.8,198.997
66.5148,240.5151.1,17766.5148,113.5
163.8,155.003″/>
</TransformDecorator>
</Canvas>
注意,如果在同一TransformCollection对象中指定另外的变形,则需要被封闭在TransformCollection中。而且,分析和应用每个变形的顺序在最终效果中产生差异。例如,在将一个元素平移到不同的屏幕坐标之前旋转该元素可产生差异。
下面的例子示出应用于两个折线元素的旋转和平移:
<!--旋转,然后平移-->
<TransformDecorator AffectsLayout=″false″>
<TransformDecorator.Transform>
<TransformCollection>
<RotateTransform Angle=″45″/>
<TranslateTransformX=″100″Y=″100″/>
</TransformCollection>
</TransformDecorator.Transform>
<Polyline ID=″box4″
Stroke=″Green″
StrokeThickness=″5″
Points=″0,0 10,10,10,50 50,50 50,10,10,10″>
</Polyline>
</TransformDecorator>
<!--平移,然后旋转-->
<TransformDecorator AffectsLayout=″false″>
<TransformDecorator.Transform>
<TransformCollection>
<TranslateTransform X=″200″Y=″200″/>
<RotateTransform Angle=″15″/>
</TransformCollection>
</TransformDecorator.Transform>
<Polyline ID=″box5″
Stroke=″Cyan″
StrokeThickness=″5″
Points=″0,0 10,10 10,50 50,50 50,10 10,10″>
</Polyline>
</TransformDecorator>
注意,这两个变形没有为它们相应的形状产生相同的最终屏幕位置。当使用旋转变形时,该变形旋转特定元素的整个坐标系统。取决于元素相对于原点的位置,旋转的效果可能不是要在“原地”旋转它。例如,对于一个位于沿x轴从零起200单位的元素,例如,30度的旋转具有沿半径为200围绕原点绘制的圆旋转该元素30度的效果。为此,当处理一个Transform以将元素平移到原点、应用旋转、偏移或缩放变换,然后将该元素平移回它的最后位置时,它更为简单。
可使用特定句法来指定围绕特定点旋转,与在变换设置中其它平移无关。实际上,这个句法指定到新原点的平移、旋转和回到先前原点的平移。为了指定围绕点(cx,cy)旋转r度,使用下面的句法:
transform=″rotate(rx[cx,cy])″
偏斜变换使开发者能够沿一或多个畸变形状。SkewTransform(偏斜变换)类提供AngleX(X轴角度)和AngleY(Y轴角度)属性,它们指定沿每一轴的比例偏移。
<Canvas ID=″root″
xmlns=″http://schemas.microsoft.com/2003/xaml″>
<!--在X轴方向偏斜-->
<TransformDecorator AffectsLayout=″false″>
<TransformDecorator.Transform>
<TransformCollection>
<SkewTransform AngleX=″30″/>
<TranslateTransformX=″0″Y=″100″/>
</TransformCollection>
</TransformDecorator.Transform>
<Rectangle
RectangleTop=″30″
RectangleLeft=″30″
RectangleWidth=″80″
RectangleHeight=″50″
Stroke=″Red″
StrokeThickness=″5″/>
</TransformDecorator>
<!--在Y轴方向偏斜--><TransformDecorator AffectsLayout=″false″>
<TransformDecorator.Transform>
<TransformCollection>
<SkewTransform AngleY=″10″/>
<TranslateTransform X=″0″Y=″200″/>
</TransformCollection>
</TransformDecorator.Transform>
<Rectangle
RectangleTop=″30″
RectangleLeft=″30″
RectangleWidth=″80″
RectangleHeight=″50″
Stroke=″Blue″
StrokeThickness=″5″>
</Rectangle>
</TransformDecorator>
相对于其它变形,应用偏斜变形的效果是偏斜坐标系统,而不仅是形状。因而,坐标系统是从原点偏斜的,只要设置了原点。如果在离开原点有一定距离的形状上进行偏斜变形,则“空的空间(empty space)”也反映偏斜,影响元素定位。为了相同的原因,开发者应用定位变形的顺序影响所呈现的偏斜或旋转。
任何时候要将颜色添加到形状或控件就使用画刷。本发明提供标记,使开发者的应用能够用来自简单的纯色到一组复杂图案和图像的任何一种来绘画用户界面(UI)元素。
Brush可以着色在画布上绘制的形状的内部和边缘。它们也可以用于改变构成UI的任何元素的外观。下面是Brush类型的某些属性并且可以接受任何画刷:
Control.Background
Control.BorderBrush
Column.Background
Text.Foreground
Shape.Fill
Shape.Stroke
有两种主要类型的画刷,即向量和位图画刷。基于向量的画刷包括SolidColorBrush(纯色画刷)、LinearGradientBrush(线性渐变画刷)、RadialGradientBrush(径向渐变画刷)、DrawingBrush(绘制画刷)(尽管DrawingBrush可以包括用位图填充的形状)。基于位图的画刷包括ImageBrush(图像画刷)和NineGridBrush(九格栅画刷)。通常,位图在拉伸或缩放以填充一个区域时丢失质量;而向量不会。因此,只要可能,应当使用基于向量的画刷。
填充的基本类型是SolidColorBrush,它用纯色填充区域。有若干方法指定纯色。众所周知的颜色可以按名称来选择。例如,形状的Fill属性可以设置为“Red(红)”。可以通过指定红、绿和蓝的量以组合成单一纯色来从32位颜色调色板来选择颜色。用于从32位调色板指定颜色的格式是“#RRGGBB”,其中RR是两位十六进制数字指定红的相对量,GG指定绿的量,而BB指定蓝的量。另外,可以将颜色指定为“#AARRGGBB”,其中AA指定颜色的alpha信道,或透明性。其它颜色方案是可行的。
在下面的例子中,Ellipse元素的Fill是使用预定的颜色名称来设置的。
<Canvas
xmlns=″http://schemas.microsoft.com/2003/xaml″>
<Ellipse
Fill=″Red″
CenterX=″80″
CenterY=″80″
RadiusX=″50″
RadiusY=″50″/>
</Canvas>
尽管alpha信道可以直接以任何纯色画刷来指定,但它也可以用画刷的Opacity属性来指定。整个元素的不透明性及其子元素可使用UIElement.(Opacity)属性来指定。这些值的每一个被指定为零与一之间的Double(双精度型)。值为一是完全不透明的,而值为零是完全透明的。描述不透明性的不同方法是累积的。即,如果alpha信道为0 x 7F(50%不透明性)且UIElement.Opacity属性为0.5(50%不透明性),则以25%不透明性绘画元素。
渐变画刷是沿一个轴从一个颜色改变到另一个颜色的填充。在向量图形(Vector Graphics)中支持两种类型渐变:线性和径向渐变。
渐变画刷的基本构件是渐变停止符。渐变停止符沿渐变轴在相对偏移处指定一种颜色。在渐变停止符之间的点的颜色是按照由两个边界渐变停止符指定的颜色的组合来线性内插的。偏移是范围从零到一的Double。下面阐述Gradient的例子。
拥有Gradient画刷的一种方法是通过显式地指定渐变停止符。下面是一个例子:
<Button.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color=″Red″Offset=″0″/>
<GradientStop Color=″Blue″Offset=″0.25″/>
<GradientStop Color=″Orange″Offset=″0.75″/>
<GradientStop Color=″Yellow″Offset=″1″/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Button.Background>
在下面的例子中,LinearGradientBrush用于用具有四个渐变停止符的线性渐变来填充一个Button(按钮)的Background(背景)。
<Button.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color=″Red″Offset=″0″/>
<GradientStop Color=″Blue″Offset=″0.25″/>
<GradientStop Color=″Orange″Offset=″0.75″/>
<GradientStop Color=″Yellow″Offset=″1″/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Button.Background>
RadialGradientBrush用于用径向渐变填充区域。径向渐变与线性渐变相似,但渐变轴是从椭圆的内部到外部。用径向渐变填充的圆可能具有黄色中心和绿色轮廓,在它们之间是内插的颜色。下面的图像示出用从白色变成灰色的径向渐变填充的矩形。外面的圆表示渐变圆,而红点表示焦点。这个渐变具有其SpreadMethod(散布方法)被设置为Pad(填充)。
在下面的例子中,使用RadialGradientBrush设置Rectangle元素的Fill属性。径向渐变具有焦点(0.5,0.5)。
<Rectangle.Fill>
<RadialGradientBrush Focus=″0.5,0.5″>
<RadialGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color=″red″Offset=″0″/>
<GradientStop Color=″yellow″Offset=″1″/>
<GradientStop Color=″blue″Offset=″0.5″/>
</GradientStopCollection>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Rectangle.Fill>
当创建只具有两种颜色的渐变时,可以使用关键字用于笔画、填充和背景属性以简化符号。下面的示例示出如何创建用水平渐变填充的矩形,这是一种线性渐变类型,从蓝色改变成红色。
<Rectangle
Fill=″HorizontalGradient Blue Red″
RectangleLeft=″120″
RectangleTop=″120″
RectangleWidth=″100″
RectangleHeight=″100″/>
创建水平、垂直和径向渐变的简短句法如下:GradientType StartColorEndColor(渐变类型起始颜色终止颜色),其中GradientType是VerticalGradient(垂直渐变)、HorizontalGradient(水平渐变)或RadialGradient(径向渐变)。StartColor和EndColor可以是预定的颜色名称(诸如蓝)或十六进制值。
垂直渐变是其起点和终点形成垂直线的线性渐变;相似地,水平渐变是其起点和终点形成水平线的线性渐变。开发者可以显式地使用下面的句法描述其自己的两色线性渐变:LinearGradient StartPoint EndPoint StartColorEndColor(线性渐变起点终点起始颜色终止颜色),其中StartPoint和EndPoint是起始和终止坐标,其中每个坐标表达为一对从零到一的x和y值,诸如0.1,0.1和0.5,0.5。这些值表示起点和终点的相对位置;0.5,0.5的终点定位在填充区域右边的50%处和从该区域的顶部起的路线的50%处--在该形状中间设置该点。
在下面的例子中,Rectangle元素的Fill属性是使用线性渐变显式设置的。
<Rectangle
Fill=″LinearGradient0.1,0.1 0.5,0.5Blue Green″
RectangleLeft=″220″
RectangleTop=″220″
RectangleWidth=″100″
Rectangl eHei ght=″100″/>
下面的例子示范如何使用简短句法用两色径向渐变填充区域:
<Rectangle
Fill=″RadialGradient Blue Red″
RectangleLeft=″320″
RectangleTop=″320″
RectangleWidth=″100″
RectangleHeight=″100″/>
除Fill属性之外,渐变也可以用于填充对象的轮廓,如Shape元素的Stroke。
绘制画刷使之有可能用其它形状和画刷的组合来填充形状或控件。DrawingBrush内的Shape,不像普通的Shape元素,不是元素树中的元素,而是,它们直接由媒体层分析和呈现。这可以在用户界面的部分是由许多形状组成的情况下产生显著改进的性能。
绘制画刷是TileBrush(平铺画刷)类型的。该部分提供关于开发者可以用于控制绘制画刷如何填充其输出区域的附加特征的信息。
ImageBrush(图像画刷)用位图图像填充区域。下面的示例示出如何使用ImageBrush呈现一个图像作为Canvas的背景。
<Canvas Height=″400″Width=″600″
xmlns=″http://schema.microsoft.com/2003/xaml″>
<Canvas.Background>
<ImageBrush>
Stretch=″Uniform″
HorizontalAlignment=″Left″
VerticalAlignment=”Top”
ImageSource=″gecko.jpg″/>
</Canvas.Background>
</Canvas>
图像画刷是Tile Brush类型的。该部分提供关于开发者可以用于控制图像如何填充其输出区域的附加特征的信息。
DrawingBrush和ImageBrush两者都是平铺画刷类型的(它们从TileBrush类导出)。因此,它们具有一组共同的特征,使开发者能够控制如何填充区域的大量细节。例如,代替仅用单一拉伸的图像填充区域,开发者可以用创建一种图案的一系列图像平铺填充区域。
平铺画刷描述用内容填充的一或多个平铺。ImageBrush是用位图图像填充其平铺的平铺画刷。DrawingBrush是用绘制填充其平铺的平铺画刷。
平铺画刷为开发者提供两层控制;开发者可以控制画刷的内容如何填充其平铺,而且开发者可以控制画刷的平铺如何填充区域。默认地,平铺画刷用单一平铺填充输出区域,并且拉伸画刷的内容以填充该平铺。使开发者能够覆盖这个默认行为的一些属性是Stretch(拉伸)、ViewPort(视区)和ViewBox(视框)属性。Stretch属性(下面还参考图18描述)定义画刷的内容如何填充其平铺。ViewPort定义画刷的平铺的尺寸和位置,而ViewBox属性确定画刷的内容的尺寸和位置。
Stretch属性控制平铺画刷的内容如何拉伸以填充其平铺。Stretch属性接受下列由Stretch枚举定义的值:
None(无):不拉伸画刷的内容以填充平铺。Fill(填充):缩放画刷的内容以适合平铺。因为内容的高度和宽度是独立地缩放的,所以可能不保持内容的原始纵横比。即,画刷的内容可能被弯曲以便完全填充输出平铺。Uniform(均匀):缩放画刷的内容,使得它完成适合在平铺内。保持内容的纵横比。UniformToFill(均匀填充):缩放画刷的内容,使得它完全填充输出区域,同时保持内容的原始纵横比。
HorizontalAlignment(水平对齐)和VerticalAlignment(垂直对齐)属性确定平铺画刷的内容如何在其平铺内对齐。HorizontalAlignment属性接受下列由HorizontalAlignment枚举定义的值:Left(左)、Center(居中)和Right(右)。VerticalAlignment属性接受下列由VerticalAlignment枚举定义的值:Top(上部)、Center(居中)和Bottom(下部)。
ViewPort属性确定画刷的平铺的尺寸和位置。ViewPortUnits(视区单位)属性确定是使用绝对或相对坐标指定ViewPort。如果坐标是相对的,则它们相对于输出区域的尺寸。点(0,0)表示输出区域的左上角,而(1,1)表示输出区域的右下角。为了指定ViewPort属性使用绝对坐标,设置ViewPortUnits属性为Absolute(绝对)。
在下面的例子中,使用图像创建一个具有宽度和高度为100且其它左上角在(0,0)处的平铺。
<Rectangle.Fill>
<ImageBrush ViewPort=″0,0100,100″
ViewPortUnits=″Absolute″
ImageSource=″help.GIF″TileMode=″Tile″/>
</Rectangle.Fill>
画刷的内容的尺寸和位置可以使用ViewBox属性来指定。当平铺画刷的平铺没有完全填充输出区域时,其TileMode(平铺模式)属性指定如何填充剩余的输出区域。TileMode属性接受下列由TileMode枚举定义的值:
None(无):仅绘制基平铺。Tile(平铺):绘制基平铺并且通过重复基平铺填充剩余区域,使得一个平铺的右边缘毗邻于下一个的左边缘,且下部和上部也是如此。FlipX(沿X轴翻转):与Tile相同,但水平地翻转交替列的平铺。FlipY(沿Y轴翻转):与Tile相同,但垂直地翻转交替行的平铺。FlipXY(沿XY轴翻转):FlipX和FlipY的组合。
在下面参考图19描述不同的平铺模式。下面参考图17描述的NineGridBrush,与图像画刷非常相似,因为它用位图图像填充区域。然而,在NineGridBrush的情况下,图像被四个边划分成九个区域或格栅。更多的信息,见NineGridBrush页。
图3和4示出场景图300和400的例子,分别包括称为Visual(视件)的基对象。视件对象,或者简称为视件,是图形内容如直线、文本和图像的容器。如在图5的视件类的对象继承中所表示的,有若干不同视件对象表示的,包括ContainerVisual(容器视件),它是不直接包含图形内容的Visual,但包含子Drawing Visual(绘制视件)对象。子DrawingVisual对象被添加到ContainerVisual而不是被添加到其它DrawingVisual对象。这允许开发者作出改变并在各视件对象上设置属性而不重新创建,随后重新呈现整个绘制上下文,同时还允许访问容器对象上的剪辑和变形属性。ContainerVisual对象可以嵌套。
DrawingVisual是可以包含图形内容的视件。这个视件揭示许多绘制方法。DrawingVisual的子对象被组织在基于零的z顺序空间中。RetainedVisual()是引入可以用于绘制的“保留的指令流”的Visual。更简单地说,RetainedVisual允许开发者保留视件的内容,并且仅在必要时重新绘制它。有可能命令式地使用RetainedVisual,如DrawingVisual,通过调用RenderOpen(呈现打开)和使用返回的用于绘制的DrawingContext(绘制上下文)。RetainedVisual提供生效回调功能和InvalidateVisual(无效视件)方法。为使用生效功能,用户实现RetainedVisual上的IRetainedRender(保留呈现接口)接口或者从它导出的类。
返回图5,还有另一个视件是HwndVisual(窗口句柄视件)505,它是用于主宿传统的
控件或窗口(它们作为场景图的可视场景内的子视件)的视件。更具体地,传统程序将仍通过WM_PAINT方法(等)运行,该方法基于以前的图形技术绘制到子HWnd(窗口句柄)(等)。为在新的图形处理模型中支持这类程序,HwndVisual允许Hwnd被包含在场景图中并且在双亲视件被重新定位时被移动。其它类型的视件也是可行的,诸如三维(3D)视件,它允许在两维与三维世界之间的连接,例如,像照相机的视图有可能通过具有到三维世界中的视图的两维视件。
如图3所示,VisualManager(视件管理器)304包括连接视件树到媒体的对象。VisualManager建立视件数据结构(根视件302)与要呈现该数据的目标之间的保留连接,提供跟踪两者之间差异的可能性。VisualManager304接收窗口消息并提供方法将绘制坐标中的点变换成设备坐标且反之亦然。
典型的应用可通过用“XAML”定义布局(如在上述美国专利申请序列号10/401,707所述)并且还通过用C#指定某些绘制操作来绘制图形。开发者可创建Shape元素,或者使用具有图元的Geometry类来绘制几何形状。在下面的情况中,代码示范在Canvas之下的视件中绘制一个椭圆:
private void CreateAndShowMainWindow()
{
mainWindow=new MsAvalon.Windows.Window();
Canvas myCanvas=new Canvas();
mainWindow.Children.Add(myCanvas);
Ellipse el=new Ellipse();
el.Fill=Brushes.Blue;
el.Stroke=Brushes.Black;
el.StrokeThickness=new Length(10);
el.CenterX=new Length(100);
el.CenterY=new Length(75);
el.RadiusX=new Length(50);
el.RadiusY=new Length(50);
myCanvas.Children.Add(el);
mainWindow.Show();
}
使用Visual API,开发者可以代之以直接绘制到Visual中(否则通过布局元素来访问)。
为呈现DrawingVisual对象的内容,应用一般调用DrawingVisual上的RenderOpen方法。RenderOpen返回一个DrawingContext,应用用它可以完成绘制操作。为清除Visual的内容,应用于调用DrawingContext上的Close(关闭)。在应用调用Close之后,可以不再使用DrawingContext。
下面的代码将一个椭圆(情形与前面例子中椭圆相同)绘制到DrawingVisual中,使用Geometry对象而不是Ellipse形状。该例创建一个DrawingVisual,取得DrawingVisual的DrawingContext,并且调用DrawingContext的DrawGeometry方法绘制椭圆。注意,开发者需要添加该Visual到顶层对象的视件树,在本例中它是一个窗口。
mainWindow=new MSAvalon.Windows.Window();
mainWindow.Show();
DrawingVisual myDrawingVisual=new DrawingVisual();
DrawingContext myDrawingContext=myDrawingVisual.RenderOpen();
SolidColorBrush mySolidColorBrush=new SolidColorBrush();
mySolidColorBrush.Color=Colors.Blue;
Pen myPen=new Pen(Brushes.Black,10);
EllipseGeometry aGeometry=new EllipseGeometry(new
Point(100,75),50,50);
myDrawingContext.DrawGeometry(mySolidColorBrush,myPen,aGeometry);
myDrawingContext.Close();
((IVisual)mainWindow).Children.Add(myDrawingVisual)
下面的例子进一步在前面的例子上构建,通过添加相似的椭圆到ContainerVisual;注意本例为了清晰而冗长。使用ContainerVisual可以帮助组织场景对象,并且允许开发者分离Visual对象(在其上根据普通绘制内容进行击中测试或生效(RetainedVisual对象)),并且最小化不必要的内容重新绘制。
mainWindow=MSAvalon.Windows.Window();
mainWindow.Show();
//创建一些Visual
ContainerVisual myContainer=new ContainerVisual();
DrawingVisual myDrawingVisual=new DrawingVisual();
DrawingVisual myDrawingVisual_1=new DrawingVisual();
DrawingVisual myDrawingVisual_2=new DrawingVisual();
//执行一些绘制
DrawingContext myDrawingCoontext=myDrawingVisual.RenderOpen();
SolidColorBrush mySolidColorBrush=new SolidColorBruhs();
mySolidColorBrush.Color=Colors.Violet;
Pen myPen=new Pen(Brushes.Black,10);
EllipseGeometry sGeometry=new EllipseGeometry(new
Point(100,75),50,50);
myDrawingContext.DrawGeometry(mySolidColorBrush,myPen,aGeometry);
myDrawingContext.Close();
DrawingContext myDrawingContext_1=
myDrawingVisual_1.RenderOpen();
mySolidColorBrush.Color=Colors.Red;
Pen myPen1=new Pen(Brushed.Orange,10);
EllipseGeometry aGeometry1=new EllipseGeometry(newPoint(100,175),50,50);
myDrawingContext_1.DrawGeometry(mySolidColorBrush,myPen1,
aGeometry1);
myDrawingContext_1.Close();
DrawingContext myDrawingContext_2=
myDrawingVisual_2.RenderOpen();
mySolidColorBrush.Color=Colors.Red;
Pen myPen2=new Pen(Brushed.Orange,10);
EllipseGeometry aGeometry2=new EllipseGeometry(new
Point(100,275),50,50);
myDrawingContext_1.DrawGeometry(mySolidColorBrush,myPen2,aGeometry2);
myDrawingContext_2.Close();
//将DrawingVisual添加到ContainerVisual的VisualCollection
myContainer.Children.Add(myDrawingVisual);
myContainer.Children.Add(myDrawingVisual_1);
myContainer.Children.Add(myDrawingVisual_2);
//将ContainerVisual添加到窗口
((IVisual)mainWindow).Children.Add(myContainer);
RetainedVisual与DrawingVisual相似,但允许选择性地重新绘制视件内容。如其名称所暗示的,RetainedVisual可以保留内容用于在媒体上多次出现。它还提供回调和生效功能。这个功能可以通过给开发者在内容的重新呈现上提供更强的控制来帮助呈现性能。
在基本层,用户可以创建和使用RetainedVisual,与DrawingVisual很相似;即,用户可以调用RenderOpen并取得DrawingContext。可供替换地,用户可以实现RetainedVisual上的IRetainedRender接口。通过这么做,用户保证图形系统将使用在RenderBounds(呈现边界)属性中设置的值作为在IRetainedVisual.Render调用处要呈现的内容的边界。
当呈现场景时,图形系统将检查任何子Visual。如果RenderBounds属性值表示在呈现场景时将需要一个特定Visual的内容,则系统将调用IRetainedVisual.Render填充该Visual的内容,代替已经在存储器中的任何内容。该应用还可以调用InvalidateVisual直接从Visual刷新内容。如果该应用还没有实现在RetainedVisual上的IRetainedRender,则对InvalidateVisual的任何调用将抛出异常。
下面的代码实例化一个类,它实现在RetainedVisual上的IRetainedRender并且绘制到它之中。
public class Rectangle:RetainedVisual,
IRetainedRender
{
public Rectangle(Color color,Rect rect):
base()
{
m_color=color;
m_rect=rect;
RenderBounds=rect;
}
public void SetColor(Color color)
{
m_color=color;
InvalidateVisual();
}
public void Render(DrawingContext ctx)
{
ctx.DrawRectangle(
new SolidColorBrush(m_color),
null,
m_rect);
}
}
Visual API,与本发明的图形系统的其余部分一样,是一个受管理的API并且使用了受管理代码的典型特征,包括强类型和无用单元收集。它还利用硬件加速性能用于呈现。为方便用现有不受管理的应用工作的开发者,Visual API提供本图形系统与基于Microsoft Windows
Graphics Device Interface(图形设备接口)(GDI)的呈现服务之间的有限互操作能力。
这种互操作能力允许开发者在知道Visual的应用中使用Hwnd Visual对象来主宿基于GDI的窗口,编写控件及基于本发明的绘制和呈现的主题,但仍在传统的GDI应用中工作,并且修改基于GDI HWND的应用以利用新的呈现特征,包括硬件加速和颜色模型。
HwndVisual允许在知道Visual的应用中主宿Win32内容。如图5所示,HwndVisual从ContainerVisual继承。注意,不可能在同一HwndVisual中混合GDI和新的绘制模型。而是,这个视件对于传统的有限范围的控件可能更有用。下面的例子示范在一个HwndVisual中创建一个控件并且将它添加到视件树。
//导入Win32资源并定义控件的变量。
.
.
.
//创建控件。
hwndControl=CreateWindowEx(
0,
WC_TREEVIEW,
″″
WS_CHILD|WS_VISIBLE|TVS_HASLINES|TVS_LINESATROOT
TVS_HASBUTTONS,
x,
y,
cx,
cy,
hwndParent,
IntPtr.Zero,
IntPtr.Zero,
0);//为控件创建HwndVisual并且将它添加到预定义的集合。
s_visuall=HwndVisual1.GetHwndVisual(hwndControl);
s_visual1.Size=new Size(150,150);
s_visual1.IsHwndDpiAware=false;
s_visual0.Children.Add(s_visuall);
至于其它对象,一旦控件被主宿在Visual中,开发者就可以将变换和其它属性变化应用于控件。
TransformCollectiont=new TransformCollection();
t.AddScale(1.4,1.4);
t.AddTranslate(130,80);
s_visual0.Children.SetTransform(s_visuall,t);
如图3所示,顶层(或根)Visual 302连接到Visual管理器对象304,后者还具有与窗口(HWnd)306或相似单元(在其中为程序代码输出图形数据)的关系(例如,通过句柄)。VisualManager 304管理将顶层Visual(以及该Visual的任何子Visual)绘制到那个窗口306。图6示出VisualManager作为在这里所述的图形系统中的对象模型中的一组对象600中的一个。
为了绘制,Visual管理器304按分配器(dispatcher)308所调度的来处理(例如遍历或者传输)场景图,并且提供图形指令和其它数据给低层组件218(图2)用于它的相应窗口306,诸如在上述美国专利申请中主要描述的。场景图处理通常由分配器308以比低层组件218和/或图形子系统222的刷新速度相对较慢的速度来调度。
图3示出许多在顶层(根)Visual 302之下分层地安排的子Visual 310-314,其中一些表示为已经分别通过绘制上下文316、317(示为虚线框来表示它们的临时性质)用相关的指令表318和319填充了,例如包含Instruction List(指令表)和其它Visual。Visual还包含其它属性信息。一般而言,对基视件类的大多数访问是通过IVisual(视件接口)接口出现的,并且视件是从DependencyObject(依赖对象)导出的,如图5所示。在其它绘制图元中,指令表可包括对ImageData(图像数据)的引用。该ImageData然后可以直接通过从它取得绘制上下文或者通过具有SurfaceVisualRenderer(表面视件呈现器)(或者名为ImageDataVisualRenderer(图像数据视件呈现器))来直接修改/更新。
视件提供服务,通过提供剪辑、不透明性及可能的其它可以设置和/或通过取得方法读取的属性。另外,视件具有标记,它们控制它如何参与击中测试。Show属性用于显示/隐藏视件,例如,当false时视件不可见,否则视件可见。而且,这些对象(无论在Visual API层处还是在元素层处的Visual)存在于分层结构中。坐标系统通过这个层次结构继承下来。这样,双亲对象可以使修改呈现的一轮(rendering pass)的坐标变换进栈并且获得应用于该双亲的子对象。
视件的变换是在与该视件的连接上。换句话说,在双亲的IVisual接口上通过[Get|Set]ChildTransform来设置它。
注意坐标变换可用统一方法应用于一切,就好象它在位图中。注意这并不意味着变换总是应用于位图,而是获得呈现的内容是被变换同等影响的。作为示例,如果用户用一英寸宽的圆笔画一个圆,然后对那个圆应用X方向上两倍于它的缩放,则笔将是在左右上两英寸宽而上下只是一英寸宽。这有时称为合成或位图变换(与只影响几何形状的骨架或几何形状缩放相反)。图8示出缩放变换,其中出现在左边的未变换图像800和出现在右边的具有非统一缩放的变换图像802。图9示出缩放变换,其中出现在左边的未变换图像800和出现在右边的带有几何形状缩放的变换后图像904。
关于视件的坐标变换,TransformToDescendant(变换成子孙对象)将一个点从引用视件变换到子孙视件。将该点从引用视件的后-变换(post-transformation)坐标空间变换到子孙视件的后-变换坐标空间。TransformFromDescendant将一个点从子孙视件向上沿双亲链变换到引用视件。将该点从子孙视件的后-变换(post-transformation)坐标空间变换到引用视件的后-变换坐标空间。用户可取得一个从任何任意视件到子孙视件和从子孙视件到任何任意视件的Matrix(矩阵)。可获得用于确定Visual的内容的边界框的两个属性,即DescendantBounds(子孙边界),它是子孙对象的边界框,和ContentBounds(内容边界),它是内容的边界。对这些应用Union(并)提供总的边界。
剪辑属性设置(或取得)视件的剪辑区域。任何Geometry(图10示出几何形状类)可以用作剪辑区域,并且剪辑区域应用于Post-Transformat(后-变换)坐标空间中。在一个实现中,剪辑区域的默认设置是null(空),即没有剪辑,可以认为它是从(-∞,-∞)到(+∞,+∞)的无限大剪辑矩形。
Opactity属性取得/设置视件的不透明性值,使得根据不透明性值和所选的混合方式将视件的内容混合在绘制表面上。BlendMode(混合方式)属性可以用于设置(或取得)所使用的混合模式。例如,可在0.0与1.0之间设置不透明性(alpha)值,例如,Color(颜色)=alpha*前景色+(1.0-alpha)*背景色。在视件中可包括其它服务,如特殊效果属性,例如,模糊,单色等等。
可以在绘制上下文上使各种服务(包括变换、不透明性和剪辑)进栈和出栈,并且可以嵌套进栈/出栈操作,只要对每个进栈调用有一个适当的出栈调用。
PushTransform(进栈变换)方法使变换进栈。相对于进栈的变换执行后续的绘制操作。出栈调用使由匹配的PushTransform调用使其进栈的变换出栈:
void PushTransform(Transform transform);
void PushTransform(Matrix matrix);
void Pop();.
同样,PushOpacity(进栈不透明性)方法使不透明性值进栈。用指定的不透明性值在临时表面上呈现后续的绘制操作且随后合成到场景中。Pop()使由匹配的PushOpacity调用使其进栈的不透明性出栈:
void PushOpacity(float opacity);
void PushOpacity(FloatAnimation opacity);
void Pop();.
PushClip(进栈剪辑)方法使剪辑的几何形状进栈。后续的绘制操作被剪辑成几何形状。在后变换空间应用剪辑。Pop()使由匹配的PushClip调用使其进栈的剪辑区域出栈:
void PushClip(Geometry clip);
void Pop();.
注意,可以任意嵌套进栈操作,只要出栈操作与进栈匹配。例如,下面是有效的:
PushTransform(...),
DrawLine(...),
PushClip(...);
DrawLine(...);
Pop();
PushTransform(...);
DrawRect(...);
Pop();
Pop();
ProxyVisual(代理视件)是一种可不止一次添加到场景图中的视件,例如,在容器视件之下。由于任何由ProxyVisual引用的视件可通过从根起的多个路径到达,因此读取服务(TransformToDescendant(变换成子孙对象),TransformFromDescendant(变换自子孙对象)和HitTest)不通过ProxyVisual工作。实际上,存在一条从任何视件到视件树根的规范路径且该路径不包括任何ProxyVisual。
图4示出示例场景图400,其中在场景图中各ContainerVisual和各DrawingVisual(和其它)是相关的,并且具有多个Instruction List形式的相关联数据(例如在相应的绘制上下文中)。ContainerVisual是Visual的容器,并且各ContainerVisual可以彼此任意嵌套。ContainerVisual的子对象可以通过在ContainerVisual实现的IVisual接口上的方法来操纵。VisualCollection(视件集合)中的Visual的顺序确定呈现这些Visual的顺序,即从最低的索引到最高的索引从后至前(绘画顺序)呈现Visual。
如上所述,可以通过用各种绘制图元(包括Geometry(几何形状)、ImageSource(图像源)和MediaData(媒体数据))填充视件的绘制上下文来绘制视件。而且,存在一组通过这整个堆栈共享的资源和类。这包括Pen(笔)、Brush(画刷)、Geometry(几何形状)、Transform(变换)和Effect(效果)。DrawingContext抽象类揭示一组绘制操作,可用于填充DrawingVisual、RetainedVisual、ImageData等等。换言之,绘制上下文抽象类揭示一组绘制操作;对于每个绘制操作存在两种方法,一是用常数作为自变量,一是将动画绘制者(animator)作为自变量。
Geometry是一种类(图10),它定义向量图形骨架,没有笔划或填充。每个几何形状对象是简单形状(LineGeometry(直线几何形状)、EllipseGeometry(椭圆几何形状)、RectangleGeometry(矩形几何形状))、复杂单一形状(PathGeometry(路径几何形状))或通过指定的组合操作(例如,并、交等)形成的这类形状的列表GeometryCollection(几何形状集合)。这些对象形成如图10所示的类层次结构。
如图11所示,PathGeometry是Figure对象的集合。接着,每个Figure对象由一或多个Segment对象组成,它们实际上定义了外形的形状。Figure是Geometry的子部分,它定义段集合。这个段集合是单一连接的一系列二维Segment对象。Figure可以是具有确定面积的封闭形状,或者只是连接的一系列Segment,定义了一条曲线但没有包围的面积。
如图12所示,当绘制几何形状(例如矩形)时,可以指定画刷或笔,如下所述。而且,笔对象还具有画刷对象。画刷对象定义如何以图形方式填充平面,并且存在画刷对象的类层次结构。这在图12中由被填充的矩形1202来表示,它是在包括矩形和画刷指令和参数的视件被处理时产生的。Pen对象保持在Brush上,连同Thickness(粗细)、LineJoin(直线连接)、LineCap(直线帽)、EndCap(末端帽)、MeritLimit(斜接限度)、DashArray(虚线阵列)和DashOffset(虚线偏移)属性,如下所述。也如下所述,一些类型的Brush(诸如渐变和九格栅)自己确定尺寸。在使用时,这些画刷的尺寸是从边界框获得的,例如,当Brush的GradientUnits(渐变单位)/DestinationUnits(目的地单位)设置为RelativeToBoundingBox(相对于边界框)时,使用正在绘制的图元的边界框。如果这些属性设置为Absolute,则使用坐标空间。
本发明的图形对象模型包括Brush对象模型,它通常针对用像素覆盖平面的概念。在图13的层次结构中示出画刷类型的例子,并且在Brush基类之下,包括GradientBrush、NineGridBrush、SolidColorBrush和TileBrush。GradientBrush包括LinearGradient和RadialGradient对象。从TileBrush导出DrawingBrush和ImageBrush。这些类的另外的替换安排是可行的,例如,从TileBrush导出的可以是ImageBrush、VisualBrush、VideoBrush(视频画刷)、NineGridBrush(九格栅画刷)和DrawingBrush。注意,Brush对象可在使用它们时识别它们是如何与坐标系统相关的,并且/或者它们如何与在其上使用它们的形状的边界框相关的。通常,可从画刷在其上绘制的对象推断出诸如尺寸之类的信息。更具体地,许多画刷类型使用坐标系统来指定其某些参数。这个坐标系统可以相对于应用画刷的形状的简单边界框来定义,或者可以相对于在使用画刷时活动的坐标空间来定义。这些分别称为RelativeToBoundingBox和Absolute模式。
SolidColorBrush对象用纯色填充所标识的平面。如果存在该颜色的alpha分量,则以乘法将它与Brush基类中的相应不透明性属性组合起来。下面阐述一个示例的SolidColorBrush对象:
public sealed class System.Windows.Media.SolidColorBrush
:Brush
{
//构造函数
public SolidColorBrush();//初始化为黑色
public SolidColorBrush(Color color);
public
SolidColorBrush(System.Windows.Media.Animation.Color
Composer colorComposer;
//属性
public Color Color{get;}
public IEnumerator ColorAnimations{get;}
}
public class System.Windows.Media.SolidColorBrushBuilder
:BrushBuilder
{
//构造函数
public SolidColorBrushBuilder();
public SolidColorBrushBuilder(Color color);
public SolidColorBrushBuilder(SolidColorBrush scp);
//属性
public Color Color{get;set;}
public AnimationList ColorAnimations{get;}
//方法
public virtual Brush ToBrush();
}
GradientBrush对象,或者简单渐变,提供渐变填充,并且通过指定一组渐变停止符来绘制,这些渐变停止符沿某种进程指定颜色。渐变是通过执行在gamma(反差系数)2.2RGB颜色空间中的渐变停止符之间的线性内插来绘制的;另外通过其它gamma或其它颜色空间(HSB,CMYK等)的内插也是可行的。渐变对象的两种类型包括线性和径向渐变。
通常,渐变是由一列渐变停止符组成的。这些渐变停止符的每一个包含颜色(连同包括的alpha值)和偏移。如果不存在指定的渐变停止符,则按一种纯透明黑色来绘制画刷,好象根本不存在指定的画刷。如果只存在一个指定的渐变停止符,则按具有指定的一种颜色的纯色来绘制画刷。像其它资源类一样,渐变停止符类(在下表中的例子)是从changeable类导出的并且因而是可选择地可变的,如在美国专用申请题为“Changeable Class and Pattern to ProvideSelective Mutability in Computer Programming Environments(在计算机编程环境中提供可选择的可变性的Changeable类和模式)”中所述。
渐变是通过指定一组渐变停止符来绘制的。这些渐变停止符沿某种进程指定颜色。目前支持两种类型渐变,即线性和径向渐变。渐变是通过在指定颜色空间中的渐变停止符之间进行内插来绘制的。
渐变是由一列渐变停止符组成的。这些渐变停止符的每一个包含颜色(连同包括的alpha值)和偏移。如果不存在指定的渐变停止符,则按透明来绘制画刷(好象不存在指定的画刷)。如果只存在一个指定的渐变停止符,则按具有指定的一种颜色的纯色来绘制画刷。考虑任何具有在零到—(0.0...1.0)的范围内的偏移的渐变停止符,连同在范围(-∞...0.0]内的最大停止符和在范围[1.0...∞)内的最小停止符。如果所考虑的停止符集合包括在范围零到一之外的停止符,则在零(和/或一)处得到一个隐含的停止符,代表在这个停止符处将出现的内插颜色。而且,如果在同一偏移处设置两个或多个停止符,则在该偏移处将出现硬转变(而不是内插的)。添加停止符的顺序决定在这个偏移处的行为;要添加的第一停止符是在该偏移之前的有效颜色,要设置的最后一个停止符是在这个停止符之后的有效颜色,并且忽略在这个偏移处的任何其它停止符。
这个类像其它资源类一样是Changeable:
public sealed class System.Windows.Media.GradientStop:
Changeable
{
public GradientStop();public GradientStop(Color
color,double offset);
public GradientStop(Color color,
ColorAnimationCollection colorAnimations,
double offset,
DoubleAnimationCollection offsetAnimations);
public new GradientStop Copy();//隐藏
Changeable.Copy()
//默认为透明
[Animation(″ColorAnimat ions″)]
public Color Color{get;set;}
public ColorAnimationCollection ColorAnimations{
get;set;}
//默认为0
[Animation(″OffsetAnimations″)]
public double Offset{get;set;}
public DoubleAnimationCollection OffsetAnimations{
get;set;}
}
像SolidColorBrush一样,这具有在动画集合中嵌套的Changeable。
GradientSpreadMethod(渐变散布方法)枚举指定渐变应当如何在指定的向量或空间之外绘制。存在三个可能值,包括Pad(填充),其中使用末端颜色(第一个和最后一个)填充剩余的空间,Reflect(反射),其中以相反的顺序反复地重放这些停止符以填充空间,以及Repeat(重复),其中按顺序重复这些停止符,直到填充了空间为止。这个类型的属性的默认值是Pad:
public enum System.Windows.Media.GradientSpreadMethod
{
Pad,
Reflect,
Repeat
}
图14和15提供一些GradientSpreadMethod的例子,(尽管在灰度中而不是在彩色中)。每个形状具有从白色变成黑色的线性渐变。实线表示渐变向量。
通常,LinearGradientBrush用于用线性渐变填充区域。线性渐变定义沿一条直线的渐变。该直线的端点是由线性渐变的StartPoint和EndPoint属性定义的。默认地,线性渐变的StartPoint是(0,0),填充区域的左上角,而其EndPoint是(1,1),填充区域的右下角。如图15所示,使用默认值,所得到的渐变中的颜色是沿对角线路径内插的。从渐变的起点和终点形成的黑线在这里已经被添加,以高亮渐变的内插路径。
ColorInterpolationMode(颜色内插模式)枚举定义在渐变内颜色的内插模式。两个选项是PhysicallyLinearGamma10和PerceptuallyLinearGamma22。
public enum ColorInterpolationMode
{
//在Gamma 1.0空间中内插颜色
PhysicallyLinearGamma10,
//在Gamma 2.2空间中内插颜色
PerceptuallyLinearGamma22
}
这是一个抽象基类。
public abstract class System.Windows.Media.GradientBrush
:Brush
{
internal GradientBrush();
public new GradientBrush Copy();//隐藏
Changeable.Copy()
//默认为“PerceptuallyLinearGamma22”
public ColorINterpolationMode ColorInterpolationMode
{get;set;}
//默认为RelativeToBoundingBox
public BrushMappingMode MappingMode{get;set;}
//默认为Pad
public GradientSpreadMethod SpreadMethod{get;set;
}
//渐变停止符
public void AddStop(Color color,double offset);
public GradientStopCollection GradientStops{get;set;}
//ColorInterpolationMode
public ColorInterpolationMode ColorInterpolationMode
{get;set;}
}
如上面在Changeable部分所述,GradientBrush是关于Changeable的复杂类型,因为它的GradientStop(渐变停止符)属性本身保持Changeable。这意味着GradientBrush需要实现protected(受保护的)方法MakeUnchangeableCore(),和PropagateEventHandler(),以及Changeable子类实现的CloneCore()。也可选择实现ValidateObjectState(),如果存在构成集合的GradientStop的无效组合,例如。
LinearGradient指定沿一个向量的线性渐变。各停止符指定了沿该向量的颜色停止符。
public sealed class System.Windows.Media.LinearGradient:
Gradi entBrush
{
public LinearGradient();//初始化为透明
//用指定用于填充应用渐变的对象的两个颜色和渐变向量建立渐变。
//这隐含着GradientUnits属性的RelativeToBoundingBoxpublicLinearGradient(Color colorl,Color color2,double angle);
public LinearGrid(Color colorl,Color color2,
Point vectorStart,Point
vectorEnd);
public new LinearGradient Copy();//隐藏
Changeable.Copy()
//渐变向量起点
//默认为0,0
[Animation(″StartPointAnimations″)]
public Point StartPoint{get;set;}
public PointAnimationCollection StartPointAnimations
{get;set;}
//默认为1,1
[Animation(″EndPointAnimations″)]
public Point EndPoint{get;set;}
public PointAnimationCollection EndPointAnimations{
get;set;}
}
linear-gradient-brush:
″HorizontalGradient″comma-wsp color comma-wsp color
|
″VerticalGradient″comma-wsp color comma-wsp color|
″LinearGradient″comma-wsp coordinate-pair comma-wsp
color comma-wsp color
用于LinearGradient的标记允许用两个在偏移零和一处的颜色停止符指定LinearGradient。如果使用“LinearGradient”版本,则分别指定起点和终点。如果使用“HorizontalGradient”,则将起点设置为0,0并将终点设置为1,0。如果使用“VerticalGradient”,则将起点设置为0,0并将终点设置为0,1。在这些情况下,使用默认的MappingMode(映射模式),它是RelativeToBoundingBox。
RadialGradient在编程模型中与线性渐变相似。然而,尽管线性渐变具有定义渐变向量的起点和终点,但径向渐变具有一个圆连同一个焦点来定义渐变行为。圆定义渐变的终点--换言之,在1.0处的渐变停止符定义在圆的圆周处的颜色。焦点定义渐变的中心。在0.0处的渐变停止符定义在焦点处的颜色。图16表示(在灰度中)从白色变成黑色的RadialGradient。外面的圆表示渐变圆,而实心点表示焦点。这个渐变具有设置为Pad的SpreadMethod。
public sealed class System.Windows.Media.RadialGradient:
Gradi entBrush
{
public RadialGradient();//初始化为透明
//设置具有两种颜色的渐变。
//这隐含着GradientUnits属性的RelativeToBoundingBox
//连同在(0.5,0.5)处的中心
//0.5的半径和在(0.5,0.5)处的焦点
public RadialGradient(Color color1,Color color2);
public new RadialGradient Copy();//隐藏Changeable.Copy()
//默认为0.5,0.5
[Animation(″CenterAnimations″)]
public Point Center{get;set;}
public PointAnimationCollection CenterAnimations{get;set;}
//默认为0.5
[Animation(″RadiusXAnimations″)]
public double RadiusX{get;set;}
public DoubleAnimationCollection RadiusXAnimations{get;set;}
//默认为0.5
[Animation(″RadiusYAnimations″)]
public double RadiusY{get;set;}
public DoubleAnimationCollection RadiusYAnimations{get;set;}
//默认为0.5,0.5
[Animation(″FocusAnimations″)]
public Point Focus{get;set;}
public PointAnimationCollection FocusAnimations{get;set;}
}
用于RadialGradient的标记允许用两个分别在偏移0和1处的颜色停止符指定RadialGradient。使用默认的MappingMode,它是RelativeToBoundingBox,如默认半径为0.5:
radial-gradient-brush:
″RadialGradient″comma-wsp color comma-wsp color
TileBrush是一个抽象基类,包含描述平铺的逻辑和该平铺应当用以填充区域的方法。TileBrush的子类包含内容,并且在逻辑上定义填充无限平面的方法。
Stretch(拉伸)枚举用于描述如何将ViewBox(源坐标空间)映射到ViewPort(目的地坐标空间)。在TileBrush中使用它:
public enum System.Windows.Stretch
{
//保持原始尺寸
None,
//不保持纵横比,ViewBox填充ViewPort
Fill,
//保持纵横比,尽可能大地一致地缩放ViewBox,
//使得宽和高都适合在ViewPort内
Uniform,
//保持纵横比,尽可能小地一致地缩放ViewBox,
//使得整个ViewPort由ViewBox填充
UniformToFill,
}
图18提供拉伸例子。在这些例子中,内容是上/左对齐的。
TileMode(平铺模式)枚举用于描述是否由Tile填充空间和如何填充。TileBrush定义基Tile在何处(由ViewPort指定)。基于TileMode值填充空间的其余部分。
public enum System.Windows.Media.TileMode
{
//不平铺--只绘制基平铺,剩余区域保持透明
None,
//基本平铺方式--绘制基平铺并且通过重复基平铺填充剩余区域,
//使得一个平铺的右边缘平接下一个的左边缘,并且下面和上面一样
Tile,
//与平铺一样,但垂直地翻转平铺的交替列。
//无变换地绘制基平铺。
FlipX,
//与平铺一样,但水平地翻转平铺的交替行。
//无变换地绘制基平铺。
FlipY,
//FlipX和FlipY的组合。无变换地绘制基平铺
FlipXY}
图19提供TileMode例子。在每个例子中的最左上的平铺是基平铺。这些例子代表None,Tile,FlipX,FlipY和FlipXY。
VerticalAlignment枚举用于描述如何将内容垂直地放置在容器内:
public enum System.Windows.VerticalAlignment
{
//将内容与空间上部对齐
Top,
//垂直地居中内容
Center,
//将内容与空间下部对齐
Bottom,
}
HorizontalAlignment枚举用于描述如何水平地将内容放置在容器内。
public enum System.Windows.HorizontalAlignment
{
//将内容向空间的左边对齐
Left,
//水平地使内容居中
Center,
//将内容向空间的右边对齐
Right,
}
TileBrush属性选择要成为平铺(ViewBox)的无限平面的矩形部分,并且描述将成为正在填充的区域中的基Tile的目的地矩形(ViewPort)。剩余的目的地区域将基于TileMode属性来填充,它控制是否和如何将原平铺复制以填充剩余空间:
public abstract class System.Windows.Media.TileBrush:Brush
{
public new TileBrush Copy();//隐藏Brush.Copy()
//默认为RelativeToBoundingBox
public BrushMappingMode ViewPortUnits{get;set;}
//默认为RelativeToBoundingBox
public BrushMappingMode ContentUnits{get;set;}
//默认为Rect.Empty
[Animation(″ViewBoxAnimations″)]
public Rect ViewBox{get;set;}
public RectAnimationCollection ViewBoxAnimation{get;set;}
//默认为Fill
public Stretch Stretch{get;set;}
//默认为None
public TileMode TileMode{get;set;}
//默认为Center
public HorizontalAlgnment HorizontalAlignment{get;set;}
//默认为Center
public VerticalAlignment VerticalAlignment{get;set;}
//默认为0,0,1,1
[Animation(″ViewPortAnimation″)]
public Rect ViewPort{get;set;}
public RectAnimationCollection ViewPortAnimations{get;set;}
}
TileBrush的内容没有固有的边界,并且实际上描述无限平面。这些内容存在于它们自己的坐标空间中,并且由TileBrush填充的空间是在应用时的局部坐标空间。基于ViewBox、ViewPort、Alignments和Stretch属性将内容空间映射到局部空间中。ViewBox在内容空间中指定,并且将这个矩形映射到ViewPort矩形中。
ViewPort定义内容将最终被绘制的位置,创建这个Brush的基平铺。如果ViewPortUnits的值是Absolute,则ViewPort的值被认为在应用时是在局部空间中。如果,代之以ViewPortUnits的值是RelativeToBoundingBox,则ViewPort的值被认为在坐标空间中,其中0,0是正在绘画的对象的边界框的上/左角而1,1是同一边框的下/右角。例如,考虑正在填充的从100,100绘制到200,200的RectangleGeometry。那么,如果ViewPortUnits是Absolute,则(100,100,100,100)的ViewPort将描述整个内容区域。如果ViewPortUnits是RelativeToBoundingBox,则(0,0,1,1)的ViewPort将描述整个内容区域。如果ViewPort的Size(尺寸)为空,并且Stretch不是None,则这个Brush没有内容呈现。
在内容空间中指定ViewBox。这个矩形被变换成适合在ViewPort内,如由Alignment属性和Stretch属性确定的。如果Stretch是None,则没有缩放应用于内容。如果Stretch是Fill,则在X和Y两个方向上独立地缩放ViewBox到与ViewPort相同的尺寸。如果Stretch是Uniform或UniformToFill,则逻辑是相似的,但X和Y维是均匀地缩放的,保持内容的纵横比。如果Stretch是Uniform,则ViewBox被缩放到具有等于ViewPort的尺寸的较受约束的维。如果Stretch是UniformToFill,则ViewBox被缩放到具有等于ViewPort尺寸的较不受约束的维。考虑这个的另一种方法是Uniform和UniformToFill两者保持纵横比,但Uniform保证整个ViewBox在ViewPort内(有可能留下不被ViewBox覆盖的部分ViewPort),而UniformToFill保证整个ViewPort被ViewBox填充(有可能使部分ViewBox在ViewPort之外)。如果ViewBox的区域为空,则不应用Stretch。对齐仍将发生,并且它将放置″点″ViewBox。
一旦确定了ViewPort(基于ViewPortUnits)和确定了ViewBox的目的地大小(基于Stretch),ViewBox就需要被定位在ViewPort内。如果ViewBox与ViewPort是相同尺寸(如果Stretch是Fill,或者如果它只碰巧出现其它三个Stretch值之一),则ViewBox被放置在Origin(原点),以便与ViewPort相同。如果否,则考虑HorizontalAlignment和VerticalAlignment。基于这些属性,在X和Y维上都对齐ViewBox。如果HorizontalAlignment是Left,则ViewBox的左边缘将被放置在ViewPort的左边缘。如果是Center,则ViewBox的中央将定位在ViewPort的中央,且如果是Right,则右边缘将相遇。对Y维重复这个过程。
如果ViewBox是Empty(空),则认为它未设置。如果它未被设置,则考虑ContentUnits(内容单位)。如果ContentUnits是Absolute,则没有缩放或偏移发生,并且无变换地将内容绘制到ViewPort中。如果ContentUnits是RelativeToBoundingBox,则内容原点与ViewPort Origin对齐,并且按对象的边界框的宽度和高度缩放内容。
当用TileBrush填充空间时,如上所述地将内容映射到ViewPort中,并且剪辑成ViewPort。这形成用于填充的基平铺,并且基于Brush的TileMode填充剩余的空间。如果设置,则应用Brush的变换,它在其它映射、缩放、偏移等等之后发生。
VisualBrush是由Visual指定其内容的TileBrush。这个Brush可以用于创建复杂图案,或者它可以用于绘制其它部分场景的内容的附加拷贝。
public sealed class System.Windows.Media.VisualBrush:TileBrush
{
public VisualBrush();//初始化为透明
public VisualBrush(Visual v);
public new VisualBrush Copy();//隐藏TileBrush.Copy()
//Visual--默认为null(透明Brush)
public Visual Visual{get;set;}
}
ImageBrush是具有由ImageSource(图像源)指定内容的TileBrush。这个Brush可以用于用Image(图像)来填充空间。
public sealed class System.Windows.Media.ImageBrush:TileBrush
{
public ImageBrush();//初始化为透明内容
//设置图象,设置ViewBox为(0,0,Width,Height)
//并且设置Stretch为Fill
public ImageBrush(ImageData image);
public new ImageBrush Copy();//隐藏TileBrush.Copy()
//默认为null
public ImageSource ImageSource{get;set;}
//默认为true
//如果它为true,则ViewBox属性将被覆盖
//并且被设置为图象的原来大小
public bool SizeViewBoxToContent{get;set;
}}
VideoBrush是具有由VideoData指定的内容的TileBrush。这个Brush可以用于用视频填充空间。
public sealed class System.Windows.Media.VideoBrush:TileBrush
{
public VideoBrush();//初始化为透明内容
//设置图象,设置ViewBox到(0,0,Width,Height)
//并且设置Stretch为Fill
public VideoBrush(VideoData video);
public new VideoBrush Copy();//隐藏TileBrush.Copy()
//默认为null
public VideoData VideoData{get;set;}
//默认为true
//如果它为true,则ViewBox属性将被覆盖
//并且被实际上设置为视频的原来大小
public bool SizeViewBoxToContent{get;set;}
}
NineGridBrush是始终用它的内容图象填充对象边界框的Brush,并且图象拉伸不是纯粹通过视件缩放来完成的。图象源被四条边划分成九个矩形(因此名为NineGrid(九格栅))。在那些九个区域的每一个中图象的内容在0,1,2维上缩放,直到它们填充对象边界框为止。可以图17这个图中看到的在其中每个部分被缩放的维代表NineGrid的概念,从第一实例1702被放大成第二实例1704,具有示出由Top、Left、Bottom和Right定义的九个格栅的四种类型。在每个格栅方形中的箭头示出其中那些内容将被拉伸成符合ViewPort尺寸的维。
除了上面示出的九个格栅区域,存在一个可选的″第十″个格栅。这用附加图像的形式,该图像在ViewPort中心并且不被缩放。这可以用于在按钮的中央放置一个形状等等。这″第十个格栅″称为点符(glyph),并且由GlyphImageSource(点符图像源)揭示:
public sealed class System.Windows.Media.NineGridBrush:
Brush
{
public NineGridBrush(ImageData,
int LeftBorder,
int RightBorder,
int TopBorder,
int BottomBorder);
public NineGridBrush(ImageData,
int LeftBorder,
int RightBorder,
int TopBorder,
int BottomBorder
ImageData glyphImage);
public new NineGridBrush Copy();//隐藏Brush.Copy()
//默认为null
public ImageData ImageData{get;set;}
//默认为0
public int LeftBorder{get;set;}
//默认为0
public int RightBorder{get;set;}
//默认为0
public int TopBorder{get;set;}
//默认为0
public int BottomBorder{get;set;}
//默认为null
public ImageData GlyphImageData{get;set;}
}
注意,边界成员从图象像素中的图象边缘起计数。
Pen是用Brush和描述如何用笔划画出空间/几何形状的其它参数的对象。概念上,Pen描述如何从Geometry创建笔划区域。基于Geometry的边缘、Pen的Thickness(粗细)、PenLineJoin(笔线连接)、PenLineCap(笔线帽)等来创建一个新区域。一旦创建这个区域,就用Brush填充它。
public sealed class System.Windows.Media.Pen:Changeable
{
//构造函数
Public Pen();
public Pen(Brush brush,double thickness);
public new Pen Copy();//隐藏Changeable.Copy()
//属性
//默认为DashArrays.Solid(非虚线)
public DoubleCollection DashArray{get;set;}
//默认为0
[Animations(DashOffsetAnimations)]
public double DashOffset{get;set;}
public DoubleAnimationCollection DashOffsetAnimations{get;set;}
//默认为Flat
public PenLineCap StartLineCap{get;set;}
//默认为Flat
public PenLineCap EndLineCap{get;set;}
//默认为Flat
public PenDashCap DashCap{get;set;}
//默认为Miter
public PenLineJoin LineJoin{get;set;}
//默认为10
public double MiterLimit{get;set;}
//默认为null
public Brush Brush{get;set;}
//默认为1.0
[Animations(ThicknessAnimations)]
public double Thickness{get;set;}
public Double AnimationCollection ThicknessAnimations{get;set;}
}
PenLineCap确定如何绘制笔划所画的线的末端:
public enum System.Windows.Media.PenLineCap
{
//这实际上没有线帽--使线在线的最后一点处为方形
Flat,
//由直径等于线宽的半圆作为线帽
Round,
//由三角形作为虚线帽
Triangle,
//由边长等于线宽、以末端点为中心的正方形作为线帽
Square
}
PenDashCap(笔虚线帽)确定如何在虚线笔划画的线中绘制每段虚线的末端:
public enum System.Windows.Media.PenDashCap
{
//这实际上无虚线帽--使线在线的最后一点为方形
Flat,
//由直径等于线宽的半圆作为虚线帽
Round,
//由三角形作为虚线帽
Triangle
}
PenLineJoin确定当笔划画一条线时如何连接:
public enum System.Windows.Media.PenLineJoin
{
//在相交线段的外边缘的相交处创建尖角
Miter,
//与Miter相似,但角是圆的
Round,
//斜削式的连接,这产生斜角(diagnoal corner)
Bevel
}
DashArray类包括提供对普通的众所周知的虚线型的访问的静态属性:
public sealed System.Windows.Media.DashArrays
{
//实虚线阵列(非虚线)
public static DoubleCollection Solid{get;}
//Dash--3长1短
public static DoubleCollection Dash{get;}
//Dot--1长1短
public static DoubleCollection Dot{get;}
//DashShot--3长1短,1长1短
public static DoubleCollection DashDot{get;}
//DashDotDot--3长1短,1长1短,1长1短
public static DoubleCollection DashDotDot{get;}
}
图13所示的另一个画刷对象是VisualBrush对象。VisualBrush是由Visual指定其内容的TileBrush。这个Brush可以用于创建复杂图案,或者它可以用于绘制其它部分场景的内容的附加拷贝。
public sealed class System.Windows.Media.VisualBrush:TileBrush
{
public VisualBrush();//初始化为透明
public VisualBrush(Visual v);
public new VisualBrush Copy();//隐藏
TileBrush.Copy()
//Visual-默认为null(透明Brush)
public Visual Visual{get;set;}
}
概念上,VisualBrush提供一种方法获得以重复的平铺的方式绘制的视件作为填充。这在图12中由引用指定单一圆形状1220的视件(和任何子视件)的视件画刷表示,用该圆形状填充矩形1222。因而,VisualBrush对象可引用一个视件以定义如何绘制该画刷,它引入一种多重使用视件的类型。如此,程序可使用任意图形“元文件(metafile)”以通过画刷或笔填充区域。由于这是用于存储和使用任何图形的压缩形式,因此它用作图形源。
在一个实施例中,VisualBrush的内容没有固有的边界,并且实际上描述无限平面。这些内容存在于它们自己的坐标空间中,并且由VisualBrush填充的空间在应用时是在本地坐标空间中。基于ViewBox、ViewPort、Alignments和Stretch属性将内容空间映射到本地空间中。ViewBox在内容空间中指定,并且将这个矩形映射到ViewPort(作为通过Origin和Size属性指定的)矩形中。
ViewPort定义内容将最终被绘制的位置,创建这个Brush的基平铺。如果DestinationUnits值是UserSpaceOnUse(在使用时),则Origin和Size属性在应用时被认为在本地空间中。如果代之以DestinationUnits值是ObjectBoundingBox(对象边界框),则Origin和Size被认为在坐标空间中,其中0,0是正在绘画的对象的边界框的上/左角而1,1是同一边框的下/右角。例如,考虑正在填充的从100,100绘制到200,200的RectangleGeometry。在这样一个例子中,如果DestinationUnits是UserSpaceOnUse,则100,100的Origin和100,100的Size将描述整个内容区域。如果DestinationUnits是0bjectBoundingBox,则0,0的Origin和1,1的Size将描述整个内容区域。如果Size为空,则这个Brush没有内容呈现。
在内容空间中指定ViewBox。这个矩形被变换成适合在ViewPort内,如由Alignment属性和Stretch属性确定的。如果Stretch是None,则没有缩放应用于内容。如果Stretch是Fill,则在X和Y两个方向上独立地缩放ViewBox到与ViewPort相同的尺寸。如果Stretch是Uniform或UniformToFill,则逻辑是相似的,但X和Y维是均匀地缩放的,保持内容的纵横比。如果Stretch是Uniform,则ViewBox被缩放到具有等于ViewPort的尺寸的较受约束的维。如果Stretch是UniformToFill,则ViewBox被缩放到具有等于ViewPort尺寸的较不受约束的维。换言之,Uniform和UniformToFill保持纵横比,但Uniform保证整个ViewBox在ViewPort内(有可能留下部分ViewPort没有被ViewBox覆盖),而UniformToFill保证整个ViewPort被ViewBox填充(有可能使部分ViewBox在ViewPort之外)。如果ViewBox的区域为空,则不应用Stretch。对齐仍将发生,并且它将放置″点″ViewBox。
图18提供用各种拉伸设置呈现的图形的单个平铺1800的表示,包括在拉伸设置为“无(none)”时的平铺1800。平铺1802是当拉伸设置为“Uniform”时的表示,平铺1804是当拉伸设置为“UniformtoFill”时的表示,而当拉伸设置为“Fill”时为平铺1806。
一旦确定了ViewPort(基于DestinationUnits)和确定了ViewBox的尺寸(基于Stretch),ViewBox就需要被定位在ViewPort内。如果ViewBox与ViewPort是相同的尺寸(如果Stretch是Fill,或者如果它正好碰巧出现其它三个Stretch值之一),则ViewBox被定位在Origin,以便与ViewPort相同。否则,考虑HorizontaiAlignment和VerticalAlignment。基于这些属性,在X和Y两个维上都对齐ViewBox。如果HorizontalAlignment是Left,则ViewBox的左边缘将被放置在ViewPort的左边缘。如果是Center,则ViewBox的中央将放置在ViewPort的中央,且如果是Right,则右边缘将接合。对Y维重复这个过程。
如果ViewBox是(0,0,0,0),则认为它未设置,由此考虑ContentUnits。如果ContentUnits是UserSpaceOnUse,则没有缩放或偏移发生,并且无变换地将内容绘制到ViewPort之中。如果ContentUnits是ObjectBoundingBox,则内容原点与ViewPort原点对齐,并且按对象的边界框的宽度和高度缩放内容。
当用VisualBrush填充空间时,如上将内容映射到ViewPort中,并且剪辑成ViewPort。这形成用于填充的基平铺显示,并且基于Brush的TileMode填充剩余的空间。最后,如果设置,则应用Brush的变换--它在所有其它映射、缩放、偏移等等之后发生。
TileMode枚举用于描述是否由其Brush填充空间和如何填充。可以被平铺的Brush具有定义的平铺矩形,并且这个平铺具有在所填充空间内的基位置。基于TileMode值填充空间的其余部分。图19提供具有各种TileMode设置的示例图形,包括“None”1900,“Tile”1902,“FlipX”1904,“FlipY”1906和“FlipXY”1908。在各种示例图形中最左上的平铺包括基平铺。
图20表示为VisualBrush中的平铺定义的VisualBrush Grid(视件画刷格栅)。第一个圆是简单的格栅,而第二个具有在x方向Skew(偏斜)为47的Transform(变换)。图21示出用图像填充时的情况。
回到图13,图像画刷从平铺画刷导出并因而可以被平铺。NineGridBrush与ImageBrush非常相似,除了图像基于尺寸被弯曲。实际上,NineGridBrush可被认为是Stretch的定制类型,图像的某些部件被拉伸,然而其它部件(例如,边)不是。因而,尽管在ImageBrush中图像的Size将引起简单的缩放,但NineGridBrush将产生非均匀的缩放到所希望的尺寸。当应用画刷时,非缩放区域的单位是用户单位,这意味着ContentUnits(存在NineGridBrush有的话)将设置为UserUnitsOnUse。Brush的Transform属性可以有效地使用。注意,边成员从图像的边缘起计数。
如上面一般描述的,本发明的图形对象模型包括图7的层次结构中表示的在Transform基类之下的变换类型。构成变换的这些不同类型的组件可包括TransformList(变换列表)、TranslateTransform(平移变换)、RoateTransform(旋转变换)、ScaleTransform(缩放变换)、SkewTransform(偏斜变换)和MatrixTransform(矩阵变换)。可以动画各属性,例如,程序开发者可以动画RotateTransform的Angle(角度)属性。
用于2D计算的矩阵表示为3 x 3矩阵。对于所需要的变换,只需要六个值代替完整的3 x 3矩阵。在下面命名和定义它们。
当将一个矩阵乘以一个点时,它将该点从新的坐标系统变换到先前的坐标系统:
可以嵌套变换至任意层。每当应用新的变形时,它与将它右乘到当前的变换矩阵是一样的:
在API中的大多数地方不直接用Matrix,但代之以使用Transform类,它支持动画。
public struct System.Windows.Media.Matrix
{
//构造和设置
public Matrix();//默认为单位矩阵
public Matrix(
double m00,double m01,
double m10,double m11,
double m20,double m21);
//单位矩阵
public static readonly Matrix Identity;
public void SetIdentity();
public bool IsIdentity{get;};
public static Matrix operator*(Matrix matrixl,Matrix
matrix2);
public static Point operator*(Matrix matrix,Point point);
//这些功能用指定的变形矩阵重新初始化当前的矩阵。
public void SetTranslation(double dx,double dy);
public void SetTranslation(Size offset);
public void SetRotation(double angle);//度
public void SetRotation(double angle,Point center);//度
public void SetRotationRadians(double angle);
public void SetRotationRadians(double anale,Point center);
public void SetScaling(double sx,double sy);
public void SetScaling(double sx,double sy,Point center);
public void SetSkewX(double angle);//度
public void SetSkewY(double angle);//度
public void SetSkewXRadians(double angle);
public void SetSkewYRadians(double angle);
//这些功能用指定的变换右乘当前的矩阵
public void ApplyTranslation(double dx,double dy);
public void ApplyTranslation(Size offApply);
public void ApplyRotation(double angle);//度
public void ApplyRotation(double angle,Point center);//度
public void ApplyRotationRadians(double angle);
public void ApplyRotationRadians(double angle,Point center);
public void ApplyScaling(double sx,double sy);
public void SetScaling(double sx,double sy,Point center);
public void ApplySkewX(double angle);//度
public void ApplySkewY(double angle);//度
public void ApplySkewXRadians(double angle);
public void ApplySkewYRadians(double angle);
//倒置材料
public double Determinant{get;}
public bool IsInvertible{get;}
public void Invert();//如果!IsInvertable抛出ArgumentException(自变量异常)
public static Matrix Invert(Matrix matrix);
//单独的成员
public double M00{get;set;}
public double M01{get;set;}
public double M10{get;set;}
public double M11{get;set;}
public double M20{get;set;}
public double M21{get;set;}
}
用于向量图形的标记语言和对象模型
按照本发明一个方面,提供一种标记语言和元素对象模型,使用户程序和工具能够与场景图数据结构216交互而不要求API层212(图2)的细节的特定知识。通常,提供一种向量图形标记语言连同基于编辑格式的简单标记一起用于通过元素对象模型表达向量图形。通过这种语言,可编程标记(例如,HTML或XML类型的内容)。然后,为构建场景图,将标记分析和转换成上面描述的适当的视件API层对象。在这较高的操作层,提供元素树、属性系统和布局系统来处理大量复杂性,使得对于场景设计者在设计可能的复杂场景时更为直接。
通常,向量图形系统一般提供一组形状和其它元素,与一般属性系统的集成,分组和合成系统,以及二层(元素层和资源层)方法,使得用户能够用满足灵活性和性能需求的方法编程。为了与本发明的一个方面保持一致,用于处理向量图形的元素对象模型与场景图对象模型相关。换言之,向量图形系统和VisualAPI层在元素对象模型层共享一组资源,例如,当在Visual API层上绘制时使用Brush对象并且它也是Shape上的填充属性的类型。因而,除了具有与场景图对象相关的元素,该标记语言与Visual API层共享许多图元资源(例如,画刷,变换等等)。向量图形系统还揭示和扩展Visual API层的动画性能,它在很大程度上在这些层之间共享。
而且,如下所述,向量图形系统可以编程到不同的简档或层,包括元素层和资源层。在元素层中,每个绘制形状表示为在与页面/屏幕中其余的可编程元素相同的层上的元素。这意味着形状以完全方式与布局系统、事件和属性交互动作。在资源层中,向量图形系统以纯资源格式操作,与传统的图形元文件相似。资源层是有效的,但具有某种程度对级联属性、事件化和细粒度可编程能力的有限支持。场景设计者因而在必要时具有与编程能力平衡效率的能力。
按照本发明的一个方面,在资源层上的向量图形系统还与视件API层相关,因为资源层标记,在一个实现中,表达为VisualBrush。当资源标记被分析时,创建视件对象。该视件对象被设置到一个可由形状、控件和元素层上的其它元素使用的VisualBrush之中。
图22示出元素类层次结构2200。本发明的标记语言对象模型的类通过有阴影的方框表示,并且包括形状类2502,图像类2504,视频类2206和画布类2208。形状类的元素包括矩形2210,折线2212,多边形2214,路径2216,直线2218和椭圆2220。注意,在某些实现中,圆元素不能如由图22中的虚线框2222所表示地出现,然而为了这里的各种例子,将描述圆元素2222。每个元素可包括或者与填充(属性)数据、笔画数据、剪辑数据、变形数据、过滤器效果数据和屏蔽数据相关联。
如下面描述的,形状相应于用继承的和级联的显示属性绘制的几何形状。这些显示属性用于构建绘制形状所需的笔和画刷。在一个实现中,形状是完整的呈现器(presenter),像其它控件元素一样。然而,在其它实现中,可提供画布类2508作为形状的容器,并且形状只有在画布元素中才能被绘制。例如,为保持形状轻量,不允许形状具有附属的呈现器。反之画布具有附属的呈现器并且绘制形状。下面更详细地描述画布元素。
也如下所述,图像类比形状更专用,并且例如可以包括边界数据,它可以是复杂的。例如,边界可以被指定为在上面一种颜色,在边上一种不同的颜色,有可能带有指定的不同粗细和设置的其它属性。可为图像或相似方框化的元素设置位置、尺寸旋转和缩放,诸如文本或视频。注意,图像和视频元素可以在画布元素之外存在和显示,并且也从BoxedElement(方框化元素)继承,例如,以从该元素取得背景、边界和填充支持。
视频元素允许视频(或相似的多媒体)在被显示的元素内播放。如此,向量图形系统提供一种标记接口到API层,它与各种多媒体包括文本、2D图形、3D图形、动画、视频、静止图像和音频无缝地相容。这允许学会与一种媒体一起工作的设计者容易地将其它媒体集成到应用和文档中。向量图形系统还使多媒体能够以与其它元素相同的方式动画,再次允许设计者有能力像其它元素一样使用多媒体,但不牺牲每种独立的媒体类型的核心固有唯一性。例如,设计者可以使用相同命名的模式用于在不同媒体类型上的旋转、缩放、动画、绘制、合成和其它效果,因而设计者可容易地创建非常丰富的应用,并且允许在下面构建非常有效的呈现和合成实现。
图23示出一个实现,其中标记代码2302是由分析器/译码器2304解释的。通常,分析器/译码器2304添加元素到元素树/属性系统208(也示于图2)并且将呈现器附到那些元素上。布局系统210然后取带有所附呈现器的元素树210并且将数据转换成对象并且调用视件API层212。注意,不是所有元素需要被转换,只有带有所附呈现器的那些要被转换。
通常,标记被解析为对象,其中用于XAML标记的XML模式通常在标记文件的顶部声明,如下:
<Canvas
xmlns=″http://schemas.microsoft.com/2003/xaml″
xmlns:def=″Definition″
def:Class=″Surfin.ChannelBrowser″
def:CodeBehind=″ChannelBrowser.xaml.cs″
ID=″mainCanvas″Background=″Black″
Width=″100%″Height=″100%″
Loaded=″PageLoaded″>
例如,当使用<Path>标签时,分析器使用该模式来查找有关名字空间(例如,System.windows.Shapes)以解析和构建对象。
通常,元素是参与属性系统、事件化和布局/显示系统的元素层中的对象。分析器找到标签并且决定那些标签是否帮助定义一个元素或者一个资源对象。在VisualBrush的特殊情况下,相同的标签可被解释为元素或者也可被解释为资源对象,取决于那些标签出现的上下文,例如,取决于是否出现在复杂属性句法中。
按照本发明的一个方面,标记语言提供不同方法来描述资源,包括简单串格式或复杂对象符号。对于简单串格式,分析器/译码器2304使用类型转换器2308,后者用于将串转换成适当的视件API对象。作为例子,在下面的标记行中,通过类型转换器2308,Fi1l属性值可以被转换成画刷对象:
<Circle CenterX=″10″CenterY=″10″Radius=″5″Fill=″Red″
/>
如可以容易地意识到的,将这样的带有简单的参数串、基于标签的标记内联行转换成画刷对象是直接的,并且提供一种简单的方法让场景设计者将形状及其属性添加到场景。
然而,有这样的时候,即填充属性太复杂而不能适合于一个单一的串。在这样的情况下,复杂属性句法,可以内联在标记中,用于设置该属性。例如,下面的复杂属性句法用渐变而不纯色填充一个圆,在不同渐变停止符处(范围可以从0到1)指定颜色:
<Circle CenterX=″10″CenterY=″10″Radius=″5″>
<Circle.Fill>
<LinearGradient>
<GradientStop Color=″Red″Offset=″0″/>
<GradientStop Color=″Blue″Offset=″0.33″/>
<GradientStop Color=″Green″Offset=″0.66″/>
<GradientStop Color=″Red″Offset=″1.0″/>
</LinearGradient>
</Circle.Fill>
</Circle>
除了在标记中出现内联,资源实例可定位在任何地方(例如,在标记中或者在文件中,可以在本地或者在远程网络并适当地下载),并且按名称引用,(例如,文本名称,引用或其它适当的标识符)。如此,场景设计者可以在整个场景中重用元素树中的一个元素,包括由复杂属性句法描述的元素。
分析器处理用复杂属性句法的标记,通过在必要时访问类型转换器2308,并且还将指定的参数匹配对象模型,从而为场景设计者处理场景的复杂性。因而,分析器不仅建立对象,而且还设置对象上的属性。注意,分析器实际上实例化一个构建器来创建对象,因为对象是不可变的。
因为在元素层和API层共享相同的呈现模型,所以许多对象实际上是相同的。这使得分析/转换效率很高,并且还允许不同类型的编程语言(例如,类似C#的语言)有能力容易地将标记转换成其自己的句法,并且反之亦然。注意,如图23所示,另一种这样的编程语言2310可以添加元素到元素树208上,或者可以直接与视件API层212接口。
如图23所示并且按照本发明一个方面,相同的标记2302可用于在元素层和资源层上编程。如上所述,元素层给场景设计者完整的编程能力、提供继承(例如,类似样式表的特征)和事件化(例如,由此一个元素可具有附属的代码以在响应于用户输入事件时改变其外观、位置等)的属性系统的使用。然而,本发明还提供资源层机制,通过该机制场景设计者实质上可以简捷化元素树和布局系统并且直接对视件API层编程。对于不需要元素层特征的许多类型的静态形状、图像等,这提供更有效和轻量的方法来输出适当的对象。为此,分析器识别何时存在类型“视件画刷”的填充,并且直接用资源层数据2312调用API层213来创建对象。换言之,如图22所示,元素层向量图形被分析成所创建的元素,这稍后需要转换成对象,同时资源层向量图形被分析并且以有效方式直接被存储。
作为例子,下面的标记是直接从LinearGradient的对象模型导出的,并且用VisualBrush填充外圆。该VisualBrush的内容是由内部标记定义的。注意,这种句法通常用于表达各种画刷、变换和动画:
<Circle CenterX=″10″CenterY=″10″Radius=″5″>
<Circle.Fill>
<VisualBrush xmlns=″...″>
<Circle CenterX=″0.5″CenterY=″0.5″Radius=″0.25″Fill=″Blue″/>
<Circle CenterX=″0.6″CenterY=″0.6″Radius=″0.25″Fill=″Green″/>
<Circle CenterX=″0.7″CenterY=″0.7″Radius=″0.25″Fill=″Red″/>
<Circle CenterX=″0.8″CenterY=″0.8″Radius=″0.25″Fill=″LemonChiffon″/>
</VisualBrush>
</Circle.Fill>
</Circle>
注意,尽管这些视件画刷填充的对象被有效地存储,但资源层数据(或者由此创建的对象)可以由元素和元素树208的部分来引用,如图23一般表示的。为此,这些视件画刷资源可被命名(例如,用名称、引用或其它适当的标识符)和像通过复杂属性句法所述的其它资源一样被引用。
转到对画布的说明,如上面提到的在一个替换的实现中,形状可保持轻量并且因而可被要求包含在画布中。在这个可替换的实现中,当呈现内容时,它被呈现到无限的、设备无关的画布上,而画布具有相关联的坐标系统。画布元素因而可按照绝对坐标定位内容。画布元素可以任选地定义视区,它指定剪辑、变形、较佳的纵横比和将视区映射到双亲空间的方法。如果没有建立的视区,则画布元素只指定绘图图元的分组并且可以建立变形、不透明性和其它合成属性。
下面是示例画布的标记例子:
<Canvas Background=″black″Top=″100″Left=″100″Height=″600″
Width=″800″>
<Rectangle Top=″600″Left=″100″Width=″100″Height=″50″Fill=″red″
Stroke=″blue″StrokeWidth=″10″/>
<Line x1=″100″y1=″300″x2=″300″y2=″100″Stroke=″green″
StrokeWidth=″5″/>
</Canvas>
注意,在一个实现中,当在没有单位的情况下指定坐标时,那么它们被认为是一英寸的96分之一的“逻辑像素”,并且在上例中,行将是200像素长。除了坐标,其它属性包括宽度、高度水平和垂直对齐,和ViewBox(关于类型rect(矩形)的;默认为未设置或者(0,0,0,0),意味着没有进行调整,并且拉伸和对齐属性被忽略)。如上面主要参考图18-20描述的,其它属性包括拉伸,这在未指定保持原始尺寸时,或者可以1)指定fill,其中不保持纵横比并且缩放内容以填充由上/左/宽/高确定的边界,2)指定uniform,它一致地缩放尺寸直到图像适合于由上/左/宽/高确定的边界为止,或者3)指定UniformToFill,它均匀地缩放尺寸以填充由上/左/宽/高确定的边界,并且在必要时剪辑。
为进一步与较低层对象模型联系起来,变形属性为元素的子对象建立新的坐标框架,同时剪辑属性以按边界框定义的默认剪辑路径限制在画布上可以绘制内容的区域。ZIndex(Z索引)属性可以用于指定在面板内嵌套的画布元素的呈现顺序。
ViewBox指定内容的新坐标系统,例如,通过重新定义视区的范围和原点。拉伸帮助指定那些内容如何映射到视区中。ViewBox属性的值是四个“无单位”数字<min-x>,<min-y>,<width>和<height>的列表,例如,由空白和/或逗号分开,并且是Rect类型的。ViewBox rect指定映射到边界框的用户空间中的矩形。它与插入scaleX和scaleY一样工作。拉伸属性(在这种情况下选项不是none(无))为保持图形的纵横比提供附加的控制。将附加的变形应用于给定元素的子孙对象以实现指定的效果。
在上例中,在上面的标记示例中的矩形的实际结果在每种拉伸规则下将是:
None(无)-从(100,600)到(200,650)
Fill(填充)-从(100,100)到(900,700)
Uniform(均匀)-从(100,?)到(900,?)-新高度将是400,并且它将基于HorizontalAlign和VerticalAlign而居中。
UniformToFill(均匀填充)-从(?,100)到(?,700)新宽度是1200,并且将再次基于HorizontalAlign和VerticalAlign而居中。
如果在画布上存在变换,则实际上在到ViewBox的映射上(例如,在树中)应用它。注意,这个映射将拉伸画布中的任何元素,例如,方框、文本等等,不只是形状。而且,注意,如果指定了视框,则画布不再确定其内容的尺寸,而具有指定的尺寸。如果还指定了y-宽度和y-高度,则拉伸/对齐属性用于使视框适合于指定的宽度和高度。
在对象模型中的元素可以各自具有一个应用的‘剪辑’属性。在某些元素上,尤其是形状,这直接被揭示为公共语言运行库属性,尽管在其它元素(例如,大多数控件)上通过DynamicProperty(动态属性)设置该属性。
通常,剪辑路径限制可以绘制内容的区域,如图24主要示出的,其中以未剪辑的形式2402和指定剪辑路径的形式2404(其中虚线表示剪辑路径)示出的按钮。概念上,位于以当前活动的剪辑路径为边界的区域之外的任何绘制部分未被绘制。剪辑路径可以被认为是一种屏蔽,其中在剪辑路径之外的那些像素是黑色的(alpha值为零),而在剪辑路径之内的那些像素是白色的(alpha值为一)(具有可能的沿阴影的边缘抗锯齿的例外)。
剪辑路径是由Geometry对象定义的,或者内联或者更典型地在资源部分中。使用元素上的“Clip”属性来使用和/或引用剪辑路径,如在下面的例子中所示:
<def:Resources>
<Geometry def:ID=″MyClip″>
<Path Data=″...″/>
<Rectangle.../>
</Geometry>
</def:Resources>
<Element Clip=″″%resource;MyClip″.../>
注意,使Clip动画与动画变形相似:
<Element>
<Element.Clip>
<Circle.../>
<Rectangle...>
<FloatAnimation.../>
</Rectangle>
</Element.Clip>
...子对象...
</Element>
路径是通过指定‘Geometry’数据和Path元素上的呈现属性如Fill、Stroke和StrokeWidth来绘制的。路径的一个示例标记是如下指定的:
<Path Data=″M 100 100 L 300 100 L 200 300 z″
Fill=″red″Stroke=″blue″StrokeWidth=″3″/>
路径‘Data’串是Geometry类型的。指定绘制路径的更冗长和完整的方法是通过复杂属性句法,如上所述。标记(诸如在下面的例子中)直接被供给上述Geometry构建器类:
<Path>
<Path.Data>
<CircleGeometry.../>
<RectangleGeometry.../>
<PathGeometry.../>
</Path.Data>
<Path.Fill value=″red″/>
<Path.Stroke value=″blue″/>
</Path>
也使用下面描述路径数据串的语法的符号来描述路径数据串:
*:0或更大
+:1或更大
?:0或1
():分组
|:分隔替换项
双引号包围的文字
下面示出用这种符号描述的路径数据串信息(注意在一个实现中,这里可指定FillMode,代替在元素层上的属性):
wvg-path:
wsp*moveto-drawto-command-groups?wsp*
moveto-drawto-command-groups:
moveto-drawto-command-group
|moveto-drawto-command-group wsp* moveto-drawto-
command-groups
moveto-drawto-command-group:
moveto wsp* drawto-commands?
drawto-commands:
drawto-command
|drawto-command wsp* drawto-commands
drawto-command:
closepath
|lineto
|horizontal-lineto
|vertical-lineto
|curveto
|smooth-curveto
|quadratic-bezier-curveto
|smooth-quadratic-bezier-curveto
|elliptical-arc
moveto:
(″M″|″m″)wsp*moveto-argument-sequence
moveto-argument-sequence:
coordinate-pair
|coordinate-pair comma-wsp?lineto-argument-sequence
closepath:
(″Z″|″z″)
lineto:
(″L″|″l″)wsp*lineto-argument-sequence
lineto-argument-sequence:
coordinate-pair
|coordinate-pair comma-wsp?lineto-argument-sequence
horizontal-lineto:
(″H″|″h″)wsp*horizontal-lineto-argument-
sequence
horizontal-lineto-argument-sequence:
coordinate
|coordinate comma-wsp?horizontal-lineto-argument
-sequence
vertical-lineto:
(″V″|″v″)wsp*vertical-lineto-argument-sequence
vertical-lineto-argument-sequence:
coordinate
|coordinate comma-wsp?vertical-lineto-argument
-sequence
curveto:
(″C″|″c″)wsp*curveto-argument-sequence
curveto-argument-sequence:
curveto-argument
|curveto-argumentcomma-wsp?curveto-argument
-sequence
curveto-argument:
coordinate-pair comma-wsp?coordinate-pair comma-wsp?
coordinate-pair
smooth-curveto:
(″S″|″s″)wsp*smooth-curveto-argument-sequence
smooth-curveto-argument-sequence:
smooth-curveto-argument
|smooth-curveto-argumentcomma-wsp?smooth-curveto
-argument-sequence
smooth-curveto-argument:
coordinate-pair comma-wsp?coordinate-pair
quadratic-bezier-curveto:
(″Q″|″q″)wsp*quadratic-bezier-curveto-argument
sequence
quadratic-bezier-curveto-argument-squence:
quadratic-bezier-curveto-argument
|quadratie-bezier-curveto-argument comma-wsp?
quadratic-bezier-curveto-argument-sequence
quadratic-bezier-curveto-argument:
coordinate-pair comma-wsp?coordinate-pair
smooth-bezier-curveto-argument:
(″T″|″t″)wsp*comma-wsp*smooth-bezier-curveto-
argument-sequence
smooth-quadratic-bezier-curveto-argument-sequence:
coordinate-pair
|coordinate-pair comma-wsp?smooth-quadratic-bezier-
curveto-argument-sequence
elliptical-arc:
(″A″|″a″)wsp*elliptical-arc-argument-sequence
elliptical-arc-argument-sequence:
elliptical-arc-argument
|elliptical-arc-argument comma-wsp?elliptical-arc-
argument-sequence
elliptical-arc-argument:
nonnegative-number comma-wsp?nonnegative-number
comma-wsp?
number comma-wsp flag comma-wsp flag comma-wsp
coordinate-pair
coordinate-pair:
coordinate comma-wsp?coordinate
coordinate:
number
nonnegative-number:
integer-constant
|floating-point-constant
number:
sign?integer-constant
|sign?floating-point-constant
flag:
″0″|″1″
comma-wsp:
(wsp+comma?wsp*)|(comma wsp*)
comma:
″,″
integer-constant:
digit-sequence
floating-point-constant:
fractional-constant exponent?
|digit-sequence exponent
factional-constant:
digit-sequence?″.″digit-sequence
|digit-sequence″.″
exponent:
(″e″|″E″)sign?digit-sequence
sign:
″+″|″-″
digit-sequence:
digit
|digit digit-sequence
digit:
″0″|″1″|″2″|″3″|″4″|″5″|″6″|″7″|″8″|
″9″
wsp:
(#x20|#x9|#xD|#xA)
图像元素(图25)表示要呈现到当前用户坐标系统内的给定矩形之中的完整文件的内容。图像(由图像标签表示的)可以引用光栅图像文件如PNG或JPEG,或者引用具有“image/wvg”的MINE类型的文件,如下例所述:
<Image Top=″200″Left=″200″Width=″100px″Height=″100px″
Source=″myimage.png″>
</Image>
下面的表提供关于图像的某些示例属性的信息:
名称 | 类型 | 读/读写 | 默认值 | 说明 |
Top | BoxUnit | | | 图像上边的坐标 |
Left | BoxUnit | | | 图像左边的坐标 |
Width | BoxUnit | | | 图像的宽度 |
Height | BoxUnit | | | 图像的高度 |
Source | ImageData | | | 图像的源 |
Dpi | Float | | 96(?) | 用于定尺寸的目标DPI |
HorizontalAlign | enum{Left(?),Center(?),Right(?)} | | Center | |
VerticalAlign | enum{Top(?),Middle(?),Bottom(?)} | | Middle | |
Stretch | enum Stretch{None,Fill,Uniform,UniformtoFill} | | None | None:保持原始尺寸Fill:不保持纵横比并且缩放内容以填充按上左宽高确定的边界Uniform:均匀地缩放尺寸直到图像适合于按上左宽高确定的边界为止。UniformToFill:均匀地缩放尺寸以填充按上左宽高确定的边界并剪辑。 |
ReadyState | enum{ | | | |
| MetaDataReady,Loading,LoadedLoadError} | | | |
LoadCounter | Int | 读 | Null | 当加载ReadyState(准备好状态)时递增的计数器 |
Name | String | | | 图像的替换文本。 |
如上所述,形状相应于用继承的和级联的显示属性绘制的几何形状。下面的表阐述上述基本形状元素(Rectangle,Ellipse,Line,Polyline,Polygon)的示例形状属性。注意,这些基本形状可具有笔画属性、填充属性,并且用作剪辑路径,具有继承特性,并且应用于元素和资源层两者;
名称 | 类型 | 读/读写 | 默认值 | 说明 |
Fill | Brush | 读写 | null | rect上边的坐标 |
FillOpacity | Float | 读写 | 1.0 | rect左边的坐标 |
Stroke | Brush | 读写 | null | rect的宽度 |
StrokeOpacity | Float | 读写 | 1.0 | rect的高度 |
StrokeWidth | BoxUnit | 读写 | 1px | 笔画的宽度。1px=1英寸的1/96 |
FillRule | enum{EvenOdd,NonZero | 读写 | EvenOdd | FillRule表示用于确定画布的什么部分被包括在形状内的算法 |
StrokeLineCap | enum{Butt,Round,Square,Diamond | 读写 | Butt | StrokeLineCap指定在开放子路径处当用笔划画它们时所使用的形状 |
| } | | | |
StrokeLineJoint | enum{Miter,Round,Bevel} | 读写 | Miter | StrokLineJoint指定当笔划画它们时在笔划所画的路径的角处所使用的形状(或者其它向量形状) |
StrokeMiterLimit | Float | 读写 | 4.0 | 在MiterLength与StrokeWidth的比例上的限制。值要>=1 |
StrokeDashArray | PointList | 读写 | null | StrokeDashArray控制用于笔划路径的虚线与间隙的图案。<dasharray>包含用空格或逗号分隔的<number>的列表,它们以用户单位指定交替的虚线和间隙的长度。如果提供奇数值,则重复值列表以产生偶数个值。因而,笔画-虚线阵列:532等价于笔画-虚线阵列:532532。 |
StrokeDashOff集合 | Point | 读写 | | StrokeDashOffset指定进入虚线图案中的距离以开始虚线。 |
Transform | Transform | 读写 | null | Transform为元素的子对象建立新的坐标框架 |
Clip | Geometry | 读写 | null | Clip限制可以在画布上应用绘画的区域。默认的剪辑路径被定义为边界框。 |
下面是一个矩形的示例标记语句:
<Rectangle Top=″600″Left=″100″Width=″100″Height=″50″
Fill=″red″Stroke=″blue″StrokeWidth=″10″/>
矩形在对象模型中具有下列属性(注意,矩形是读/写的,具有等于零的默认值,支持继承并且应用于元素和资源层两者):
名称 | 类型 | 说明 |
Top | BoxUnit | rect上边的坐标 |
Left | BoxUnit | rect左边的坐标 |
Width | BoxUnit | rect的宽度 |
Height | BoxUnit | rect的高度 |
RadiusX | BoxUnit | 用于圆角矩形,为使矩形的角变圆所使用的椭圆的X-轴半径。如果指定负的X-轴半径,则将使用半径的绝对值。 |
RadiusY | BoxUnit | 用于圆角矩形,为使矩形的角变圆所使用的椭圆的Y-轴半径。如果指定负的Y-轴半径,则将使用半径的绝对值。 |
下面是圆的示例标记句法:
<Circle CenterX=″600″CenterY=″100″Fill=″red″
Stroke=″blue″StrokeWidth=″10″/>
圆在对象模型中具有下列属性(注意,圆是读/写的,具有等于零的默认值,支持继承并且应用于元素和资源层两者):
名称 | 类型 | 说明 |
CenterX | BoxUnit | 圆中心的X坐标 |
CenterY | BoxUnit | 圆中心的Y坐标 |
Radius | BoxUnit | 圆中心的半径 |
下面是椭圆的示例标记句法:
<Ellipse CenterX=″600″CenterY=″100″Fill=″red″
Stroke=″blue″StrokeWidth=″10″/>
椭圆在对象模型中具有下列属性(注意,椭圆是读/写的,具有等于零的默认值,支持继承并且应用于元素和资源层两者):
名称 | 类型 | 说明 |
CenterX | BoxUnit | 椭圆中心的X坐标 |
CenterY | BoxUnit | 椭圆中心的Y坐标 |
RadiusX | Length | 椭圆中心的X-轴半径。如果指定负X-轴半径,则使用半径的绝对值。 |
RadiusY | Length | 椭圆中心的Y-轴半径。如果指定负Y-轴半径,则使用半径的绝对值。 |
下面是直线的示例标记句法:
<Line x1=″100″y1=″300″x2=″300″y2=″100″
StrokeWidth=″5″/>
直线在对象模型中具有下列属性(注意,直线是读/写的,具有等于零的默认值,支持继承并且应用于元素和资源层两者):
名称 | 类型 | 说明 |
X1 | BoxUnit | 直线起点的X-轴坐标。默认值是“0”。 |
Y1 | BoxUnit | 直线起点的Y-轴坐标。默认值是“0”。 |
X2 | BoxUnit | 直线终点的X-轴坐标。默认值是“0”。 |
Y2 | BoxUnit | 直线终点的Y-轴坐标。默认值是“0”。 |
‘Polyline’定义一组连接的直线段。典型地,‘Polyline’定义开放的形状。
下面是折线的示例标记句法:
<Polyline Fill=″None″Stroke=″Blue″StrokeWidth=″10cm″
Points=″50,375
150,375 150,325 250,325 250,375
350,375 350,250 450,250,450,357
550,375 550,175 650,175 650,375
750,375 750,100 850,100 850,375
950,375 950,251 050,251 050,25
1150,375″/>
折线在对象模型中具有下列属性(注意,各直线是读/写的,具有等于null的默认值,支持继承并且应用于元素和资源层两者):
名称 | 类型 | 说明 |
Points | PointCollection | 构成Polyline的点。坐标值在用户坐标空间中。 |
Polygon元素定义封闭的形状,它包括一组连接的直线段。下面是多边形的示例标记句法:
<Polygon Fill=″red″Stroke=″blue″StrokeWidth=″10″
points=″350,75 379,161 469,161 397,215
423,301 350,250 277,301 303,215
231,161 321,161″/>
多边形在对象模型中具有下列属性(注意,直线是读/写的,具有等于null的默认值,支持继承并且应用于元素和资源层两者):
名称 | 类型 | 说明 |
Points | PointCollection | 构成Polygon的点。坐标值在用户坐标系统中。如果提供奇数个坐标,则该元素错误。 |
用下面的符号描述在‘折线’和‘多边形’中点规范的语法:
*:0或更多
+:1或更多
?:0或1
():分组
|:分隔替换项
双引号包围的文字
下面在‘Polyline’和‘Polygon’元素中使用上述符号描述点规范:
list-of-points:
wsp*coordinate-pairs?wsp*
coordinate-pairs:
coordinate-pair
|coordinate-pair comma-wsp coordinate-pairs
coordinate-pair:
coordinate comma-wsp coordinate
coordinate:
number
number:
sign?integer-constant
|sign?floating-point-constant
comma-wsp:
(wsp+comma?wsp*)|(comma wsp*)
comma:
″,″
integer-constant:
digit-sequence
floating-point-constant:
fractional-constant exponent?
|digit-sequence exponent
fractional-constant:
digit-sequence?″.″digit-sequence
|digit-sequence″.″
exponent:
(″e″|″E″)sign?digit-sequence
sign:
″+″|″-″
digit-sequence:
digit
|digit digit-sequence
digit:
″0″|″1″|″2″|″3″|″4″|″5″|″6″|″7″|″8″|″9″
wsp:
(#x20|#x9|#xD|#xA)+
结论
如从上述详细描述中可看到的,提供了一种系统、方法和元素/对象模型,它们为程序代码提供各种与场景图接口的机制。该系统、方法和对象模型使用简单,但功能强大、灵活且可扩展。
尽管容易从本发明得到各种修改方案和替换结构,但在附图中示出了本发明的某些示例性实施例并且在上面详细地描述了它们。然而,应当理解,不希望将本发明限制于所揭示的特定形式,相反,希望覆盖落入本发明的精神和范围内的所有修改方案、替换结构和等价方案。