Silverlight中Shape,Geometry

 

Silverlight处理图形的效果其实还是蛮不错的,除了基本的Shape图形之外,还提供了Geometry复杂的图形,以及可以自定义的Path图形。

先看一下Shape类库的架构图:

 

其实挺简单的,我们主要关注的就是Shape下的几个类库图形。
 
首先来看看Shape类的几大属性:
 1.Fill,顾名思义就是图形的填充颜色,对Line无效
 2.Stroke,就是边框颜色
 3.StrokeThickness边框的宽度,用数字表示
 4.StrokeStartLineCap线条开始端的形状,仅Line,Polyline,以及Path有,值类型是个枚举,Round、Flat、Square、Triangle。
 5.StrokeEndLineCap线条结束段的形状,用法同上。
 6.StrokeDashArray 定义一个数组,表示当前线段以虚线显示的线段的长度,这里的值很搞笑,是一个数组,什么意思呢比如这个数组的值为"1,2,3,4",那么虚线的效果
                             就是第一个虚线段长度为1,空长度为2,第二个虚线段长度为3,空格长度为4,依次类推,没错,奇数就是线段的长度,偶数就是空格的长度.
    StrokeDashOffset 是第一个虚线段开始的偏移量,也就是在虚线段前空格多少长度,才开始虚线段。
    StrokeDashCap    虚线段开始结束段的形状,和前边的一样。
         <Line Stroke="Black" StrokeThickness="5" StrokeStartLineCap="Round" 
StrokeEndLineCap
="Square" X1="05" Y1="0" X2="300" Y2="0">
<Line.StrokeDashArray>
<!--设定的值用逗号隔开,下边的意思是第一个值为显示段的长度,第二个值为空格的长度,依次类推-->
<DoubleCollection>1,2</DoubleCollection>
</Line.StrokeDashArray>
<!--设置一个虚线开始的偏移值-->
<Line.StrokeDashOffset>2</Line.StrokeDashOffset>
<!--设置虚线开始<Line Stroke="Black" StrokeThickness="5" StrokeStartLineCap="Round"
端和结束端显示的形状,可用值和Line的LineCap一样
-->
<Line.StrokeDashCap>
<PenLineCap>Round </PenLineCap>
</Line.StrokeDashCap>
</Line>

效果如下:

7.StrokeLineJoin   设置线条顶端的图形,也就是多线段拐角处的形状,并且只对Polyline和Polygon有效
   StrokeMiterLimit 应该是只针对StrokeLineJoin="Miter"时候有效果

 8.Stretch,属性值还是None,Fill,Uniform,UniformToFill

 

图形详细介绍:

1.Rectangle和Ellipse

 

<StackPanel>
<Ellipse Fill="Yellow" Stroke="Blue"
Height
="50" Width="100" Margin="5" HorizontalAlignment="Left"></Ellipse>
<Rectangle Fill="Yellow" Stroke="Blue"
Height
="50" Width="100" Margin="5" HorizontalAlignment="Left"></Rectangle>
</StackPanel>

定义Rectangle和Ellipse非常简单,只需指定Height和width属性即可,当Rectangle的height和width相等,则是一个正方形,当Ellipse的height和width相等则是一个圆形。

另外Rectangle的另外一个属性RadiusX和 RadiusY,表示Rectangle的圆角的值,值越大圆角的弧度越大。

 <Rectangle Height="100" Width="100" RadiusX="15" RadiusY="15" HorizontalAlignment="Left">
<Rectangle.Fill>
<SolidColorBrush Color="BlueViolet"></SolidColorBrush>
</Rectangle.Fill>
</Rectangle>

 

都知道Image可以设置Stretch属性,用来指定图像对于Image控件的填充规则,有None,Fill,Uniform和UniformFill四个值可以选择。

同样,图形的Stretch属性也可以用来指定这四个值,不过这个属性说明的是控件对于容器的大小的。

Uniform,控件的高度和宽度会增加直到达到了容器的大小,也就是说控件的大小和容器的大小是有关系的,

    <Grid x:Name="LayoutRoot" Background="Green" Width="400" Height="300">
<Ellipse Stretch="Uniform" Fill="Red"></Ellipse>
</Grid>

 此时仅仅指定了容器的Height和Width,并没有给Ellipse指定具体的Height和Width

这时候的效果是,虽然指定了容器Width为400,但是由于是等比的,所以得到的图形是300*300.
 
    <Grid x:Name="LayoutRoot" Background="Green" Width="400" Height="300">
<Ellipse Stretch="Uniform" Fill="Red" Height="100" Width="200"></Ellipse>
</Grid>

此时设置了Ellipse的Height为100,width为200

同样道理,因为是等比的,所以得到的图形并不是 200*100,而是100*100,可以这么理解,当设置Stretch为Uniform的时候往往会按照Height或者Width较小的那个值

作为大小的极限。

    <Grid x:Name="LayoutRoot" Background="Green" Width="400" Height="300">
<Ellipse Stretch="Uniform" Fill="Red" Height="200" Width="100"></Ellipse>
</Grid>

同样的Height为200,width为100,得到的仍然为 100*100,这是有极限大小的。



UniformToFill,控件的高度和宽度会对称的设置直到填充整个容器.

    <Grid x:Name="LayoutRoot" Background="Green" Width="400" Height="300">
<Ellipse Stretch="UniformToFill" Fill="Red" ></Ellipse>
</Grid>

 
此时仅仅设置了容器的Width为400,heigh为300,没有给Ellipse设置Height和Width,但是我们发现,得到的图形是 400*400,因为当设置为UniformFill时候,会等比填充,
虽然容器的高度达不到400,但是图形还是 400*400的大小,由于高度不够,则其余的图形部分别切割掉了。
 
    <Grid x:Name="LayoutRoot" Background="Green" Width="400" Height="300">
<Ellipse Stretch="UniformToFill" Fill="Red" Height="100" Width="200" ></Ellipse>
</Grid>

此时设置了Ellipse的Height为100,Width为200

这个和刚才的Uniform有点相反了,Uniform总是取Height和Width中较小的值来作为极限,而UniformFill则是取较大的值来作为极限,并且把不能显示的部分给切割掉。

 

    <Grid x:Name="LayoutRoot" Background="Green" Width="400" Height="300">
<Ellipse Stretch="UniformToFill" Fill="Red" Height="200" Width="100" ></Ellipse>
</Grid>

设置的Height和Width和上个例子的值相反

可以看到,还是显示了一半,而另一半被切割了。

 

不知道大家有没有发现,当我们不给图形指定Stretch属性时候,我们的图形可能是长方形(正方形)和椭圆形(圆形),当我们指定了Stretch为Uniform时候,虽然图形没有

变化,但是图形的大小却变化了很多;当指定为UniformFill时候会发现,虽然我们的Height和width不相同,可是再也不会出现椭圆了,因为其中的一半被截掉。

其实Stretch的值为Fill的效果和设置HorizontalAlignment和VerticalAlignment为Stretch的效果一样,但是当设置了明确的width和height,HorizontalAlignment和VerticalAlignment则会被忽略

 

Tips:其实Canvas是这些图形最好的容器,因为可以通过指定Canvas.Left,Canvas.Right,Canvas.Top,Canvas.Bottom来指定控件的位置。

 

ViewBox在图形中的使用,使用ViewBox来存放Canvas(图形在其中),可以实现图形的放大和缩小。

        <!--
ViewBox有一个Stretch,默认值是Uniform
StretchDirection,值为一个枚举值有三个
如果将 Viewbox 的 StretchDirection 设置为 UpOnly,Viewbox 将只扩大其内容.
如果将 Viewbox 的 StretchDirection 设置为 DownOnly,Viewbox 将只缩小其内容。
如果将 StretchDirection 设置为 Both,Viewbox 将可以缩小或扩大其内容,默认值为Both.
-->
<Viewbox Grid.Row="1" HorizontalAlignment="Left" StretchDirection="UpOnly">
<Canvas Width="200" Height="450">
<Ellipse Fill="Yellow" Stroke="Blue" Canvas.Left="10" Canvas.Top="50"
Width
="100" Height="50" HorizontalAlignment="Left"></Ellipse>
<Rectangle Fill="Yellow" Stroke="Blue" Canvas.Left="30" Canvas.Top="40"
Width
="100" Height="50" HorizontalAlignment="Left"></Rectangle>
</Canvas>
</Viewbox>


 

 
图形可以随着浏览器的大小来改变大小,切忌当使用ViewBox时候,必须设置容器的大小,即设置Canvas的Height和Width,否则ViewBox并不知道怎么去缩小和放大。
 
 
Line
 
这个Line是非常简单的,就是一条直线
<Line Stroke="Blue" X1="5" Y1="100" X2="15" Y2="200"></Line>

 

Polyline,线段,非闭合

<Canvas>
<Polyline Stroke="Blue" StrokeThickness="5" Points="10,150 30,140 50,160 70,130
90,170 110,120 130,180 150,110 170,190 190,100 210,240">
</Polyline>
</Canvas>

 

 

Polygon,多线段,闭合

<Polygon Stroke="Blue" StrokeThickness="5" Points="10,150 30,140 50,160 70,130
90,170 110,120 130,180 150,110 170,190 190,100 210,240" Fill="Yellow">
</Polygon>
 

 

 

 

颜色的填充规则,简单的线条或图形并没有线条之间的交叉但是复杂的图形是经常出现的,当交叉之后会出现颜色的重叠或者是颜色的冲突,为了解决这个问题

就使用到了颜色的填充规则,其实这个填充规则非常简单,就是“奇数线条交叉”和“偶数线条交叉”这两种规则,通过设置FillRule属性来设置填充规则,值有

EvenOdd和Nonzero这两个值,当设置为EvenOdd时候(当线条交叉数量为奇数时候颜色不会被清除掉,当为偶数时候交叉部分的颜色则清空。),当设置为

Nonzero的时候,会有另外的规则,通过计算两个方向的线条的数量是否相同(即从Right -To-Left和Left-To-Right两个方向的线条的数量是否相同来决定

颜色是否填充,如果两个方向的数量相同,则不填充,如果两个方向的数量不同,则会填充颜色。)。

如下图,设置FillRule为EvenOdd

 
 
 设置FillRule为Nonzero

 
Line caps(线段开头或者结束的形状)
 <Polyline
Points
="10,110 100,110 50,10"
Stroke
="Black"
Canvas.Left
="150" StrokeLineJoin="Round" StrokeStartLineCap="Round"
StrokeEndLineCap
="Triangle" StrokeThickness="10" StrokeMiterLimit="5" />

 
 
 
Line join(线条的连接点的形状,Round,Miter,Bevel)
 <Polyline
Points
="10,110 110,110 10,10"
Stroke
="Black"
StrokeThickness
="10"
Canvas.Left
="150" StrokeLineJoin="Miter" />

 

 

 

 

        <Polyline
Points
="10,110 110,110 10,10"
Stroke
="Black"
StrokeThickness
="10"
Canvas.Left
="150" StrokeLineJoin="Miter" StrokeMiterLimit="2" />

设置为Miter并且设置StrokeMiterLimit为2,这个属性仅仅对设置为Miter有效,设定值之后,角会变的很尖.


 

 


 Path 和 Geometry

前边看的图形都是非常单一,或者说是很简单的,下面看下Path和Geometry,相对复杂的图形

使用Path不仅可以画出Line,Rectangle等这些简单的图形,还可以画出弧线、曲线,所有的Geometry需要包含在Path的Data属性中
 
Geometry包括如下:
LineGeometry,功能和Line一样
RectangleGeometry,功能和Rectangle一样,RectangleGeometry有三个重要的属性,Rect和RadiusX、RadiusY,
这个Rect就是相当于Rectangle的Width和Height,但是这个Rect有四个参数,前两个代表Left和Top的偏差值,第三个
就是width,第四个是Height;RadiusX和RadiusY还是圆角的属性。
 <Path Fill="Green">
            <Path.Data>
                <RectangleGeometry Rect="10,10 200,100" RadiusX="10" RadiusY="10"> 
                </RectangleGeometry>
            </Path.Data>
  </Path>

EllipseGeometry,功能和Ellipse一样,有三个属性RadiusX、RadiusY、Center。RadiusX和Ellipse的Width属性一样,RadiusY和Ellipse的Height属性一样,
Center是当前圆的中心点的值。
 <Path Fill="Yellow" Stroke="Blue">
<Path.Data>
<EllipseGeometry RadiusX="50" RadiusY="25" Center="100,25"></EllipseGeometry>
</Path.Data>
</Path>

 

GeometryGroup,功能是把多个Geometry给合并起来
   <Path Fill="Yellow" Stroke="Blue" Margin="5" Canvas.Top="10" Canvas.Left="10">
<Path.Data>
<GeometryGroup>
<RectangleGeometry Rect="0,0 100,100"></RectangleGeometry>
<EllipseGeometry Center="50,50" RadiusX="35" RadiusY="25"></EllipseGeometry>
</GeometryGroup>
</Path.Data>
</Path>

 <TextBlock FontSize="50">test test test</TextBlock>
<Path Fill="Yellow" Stroke="Blue" Margin="5" Canvas.Top="10" Canvas.Left="10">
<Path.Data>
<GeometryGroup>
<RectangleGeometry Rect="0,0 100,100"></RectangleGeometry>
<EllipseGeometry Center="50,50" RadiusX="35" RadiusY="25"></EllipseGeometry>
</GeometryGroup>
</Path.Data>
</Path>

PathGeometry,功能和Path类似
曲线和PathGeometry:
每一个PathGeometry可以包含多个PathFigure,每个PathFigure包含直线和曲线(非闭合和闭合);
PathFigure属性如下:
StartPoint,顾名思义线条的起始点;
Segments,一个集合,通过指定Segment来呈现不同的图形(下面会介绍Segment);
IsClosed,说明线条(曲线)是否闭合;
IsFilled,如果为true,则Figure的Fill属性使用Path.Fill属性。
 
PathSegment包括以下几个类型:
LineSegment,也就是一条直线,通过两点来确定一条直线。
 <Path Stroke="Blue">
<Path.Data>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="10,100">
<LineSegment Point="100,100" />
<LineSegment Point="100,50" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>

ArcSegment,在两点之间创建一个椭圆弧形,常用属性:
   Point,弧线的目标点(起始点有PathFigure来指定);
   Size,两个值,代表Width和Height,也可以用一个值代表两个值相等;
   IsLargeArc,获取或设置一个值,该值指示弧是否应大于 180 度;
   SweepDirection,获取或设置一个值,该值指定是以 Clockwise 方向还是以  Counterclockwise 方向绘制弧。
   RotationAngle ,获取或设置椭圆围绕 X 轴旋转的量(以度为单位),和转换效果类似。
 
看下IsLargeArc属性的效果:

看下SweepDirection属性的效果:

 

 
BezierSegment,在两点之间创建一个赛贝尔曲线,常用属性:
  Point1,获取或设置曲线的第一个控制点;
  Point2,获取或设置曲线的第二个控制点;
  Point3,获取或设置曲线的终点.

QuadraticBezierSegment,在两点之间创建一个二次赛贝尔曲线常用属性:
  Point1,曲线的控制点
  Point2,曲线的结束点
        <Path  Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure>
<QuadraticBezierSegment Point1="200,200" Point2="300,100"></QuadraticBezierSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>

PolyLineSegment,创建一系列线条,属性Point
 <Path Stroke="Black" StrokeThickness="1" >
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="10,100">
<PathFigure.Segments>
<PolyLineSegment Points="50,100 50,150" />
<QuadraticBezierSegment Point1="200,200" Point2="300,100"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>

直线部分是PolyLineSegment

PolyBezierSegment,表示一条或多条三次方贝塞尔曲线。
 “一条三次方贝塞尔曲线由四个点来定义:一个起点、一个终点和两个控制点。PolyBezierSegment 通过将 Points 属性设置为点集合来指定一条或多条三次方贝塞尔曲线。对于集合中的每三个点,第一个点和第二个点指定曲线的两个控制点,第三个点指定终点
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>

<!-- The StartPoint specifies the starting point of the first curve. -->
<PathFigure StartPoint="10,100">
<PathFigure.Segments>
<PathSegmentCollection>

<!-- The PolyBezierSegment specifies two cubic Bezier curves.
                                        第一条曲线是从 10,100到300,100并且以 0,0和200,0为控制点
                                        第二条曲线是从300,100到600,100,并且以300,0和400,0为控制点-->
<PolyBezierSegment Points="0,0 200,0 300,100 300,0 400,0 600,100" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>

PolyQuadraticBezierSegment,创建一些列二次赛贝尔曲线,QuadraticBezierSegment 可以有一个控制点和一个终点。PolyQuadraticBezierSegment 实质上可以有无限个控制点,这些点和终点的值作为 Points 属性值提供
 <Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<!-- The StartPoint specifies the starting point of the first curve. -->
<PathFigure StartPoint="10,100">
<PathFigure.Segments>
<PathSegmentCollection>
<!--
                                      第一个曲线从10,100到300,100,并且以200,200为控制点;
                                       第二个从200,200到30,400,并且以0,200为控制点-->
<PolyQuadraticBezierSegment Points="200,200 300,100 0,200 30,400" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>

 
 
使用Geometry来裁剪(Clip)
<Button Height="200" Width="200">
<Button.Clip>
<GeometryGroup FillRule="Nonzero">
<EllipseGeometry RadiusX="75" RadiusY="50" Center="100,150" />
<EllipseGeometry RadiusX="100" RadiusY="25" Center="200,150" />
<EllipseGeometry RadiusX="75" RadiusY="130" Center="140,140" />
</GeometryGroup>
</Button.Clip>
</Button>

到此,Shape和Geometry基本已经讲解完毕,有疏漏地方请多指教。

 

posted @ 2011-09-11 11:49  wangyafei_it  阅读(621)  评论(0编辑  收藏  举报