Silverlight处理图形的效果其实还是蛮不错的,除了基本的Shape图形之外,还提供了Geometry复杂的图形,以及可以自定义的Path图形。
先看一下Shape类库的架构图:
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
<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>
<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>
<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
<Polyline
Points="10,110 100,110 50,10"
Stroke="Black"
Canvas.Left="150" StrokeLineJoin="Round" StrokeStartLineCap="Round"
StrokeEndLineCap="Triangle" StrokeThickness="10" StrokeMiterLimit="5" />
<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 Fill="Green">
<Path.Data>
<RectangleGeometry Rect="10,10 200,100" RadiusX="10" RadiusY="10">
</RectangleGeometry>
</Path.Data>
</Path>
<Path Fill="Yellow" Stroke="Blue">
<Path.Data>
<EllipseGeometry RadiusX="50" RadiusY="25" Center="100,25"></EllipseGeometry>
</Path.Data>
</Path>
<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>
<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>
看下SweepDirection属性的效果:
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure>
<QuadraticBezierSegment Point1="200,200" Point2="300,100"></QuadraticBezierSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<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
<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>
<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>
<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基本已经讲解完毕,有疏漏地方请多指教。