【WPF学习】第四十章 画刷

  画刷填充区域,无论是元素的背景色、前景色以及边框,仍是形状的内部填充和笔画(Stroke)。最简单的画刷类型是SolidColorBrush,这种画刷填充一种固定、连续的颜色。在XAML中设置形状的Stroke或Fill属性时,使用的是SolidColorBrush画刷,他们在后台完成绘制。缓存

  下面是几个与画刷相关的更基本的方面:app

  •   画刷支持更改通知,由于他们继承自Freezable类。所以,若是改变了画刷,任何使用画刷的元素都会自动从新绘制自身。
  •   画刷支持部分透明。为此,只须要修改Opacity属性,使背景可以透过前面的内容进行显示。
  •   经过SystemBrushes类能够访问这样的画刷:此类画刷使用Windows系统设置为当前计算机定义的首选颜色。

  SolidColorBrush画刷无疑很是有用,但还有其余几个继承自System.Windows.Media.Brush的类,经过这些类可获得更新颖的效果。下表列出了全部这些类。ide

表 画刷类动画

 1、SolidColorBrush画刷this

   在大多数控件中,经过设置Foreground属性绘制文本颜色,并设置Background属性绘制文本背后的空间。形状使用相似但不一样的属性:Stroke属性用于绘制形状的边框,而Fill属性用于绘制形状的内部。spa

  可在XAML中使用颜色名设置Stroke和Fill属性,对于这种状况,WPF解析器自动建立匹配的SolidColorBrush对象。也可使用代码设置Stroke和Fill属性,但须要显示地建立SolidColorBrush对象。code

//Create a brush from a named color:
cmd.Background=new SolidColorBrush(Colors.AliceBlue);

//Create a brush from a system color:
cmd.Background=SystemColors.ControlBrush;

//Create a brush from color values:
int red=0;int green=255; int blue=0;
cmd.Foreground=new SolidColorBrush(Color.FromRgb(red,green,blue));

2、LinearGradientBrush画刷orm

  可经过LinearGradientBrush画刷建立从一种颜色变化到另外一种颜色的混合填充。xml

  下面多是最简单的渐变。该渐变从蓝色(左上角)到白色(右下角)在对角线上对矩形进行着色。对象

<Rectangle Width="150" Height="100" Margin="5">
            <Rectangle.Fill>
                <LinearGradientBrush >
                    <GradientStop Color="Blue" Offset="0"/>
                    <GradientStop Color="White" Offset="1" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

  为建立这种渐变效果,须要为每种颜色添加一个GradientStop对象,还须要在渐变中使用0~1的偏移值放置每种颜色。在该例中,用于蓝色的GradientStop对象的偏移值为0,这意味着它被放在渐变的开头。用于白色的GradientStop对象的偏移值为1,这意味着将它放在末尾。经过改变这些值,可调整渐变从一种颜色变化到另外一种颜色的速度。例如,若是将白色的GradientStop设置为0.5,渐变就会在中间(两个拐角的中点)从蓝色(左上角)混合到白色。矩形的右边将会是纯白色的。

  上面的标记建立了从一个拐角拉伸到另外一个拐角的对象填充渐变。然而,可能但愿建立自上而下或从一边向另外一边混合的渐变,或是使用不一样的对角线角度。可以使用LinearGradientBrush的StartPoint和EndPoint属性控制这些细节。能够经过这些属性选择第一种颜色开始变化的点,以及最后一种颜色结束变化的点(中间的区域被渐变混合)。但这里存在一个古怪的问题:用于开始点和结束点的坐标不是真实坐标。相反,LinearGradientBrush画刷将点(0,0)指定为但愿但愿填充的区域的左上角,将点(1,1)指定为但愿填充的区域的右下角,而无论该区域实际上有多高和多宽。

  为建立自上而下的横向填充,可将用于左上角的(0,0)点做为开始点,并将(0,1)点做为结束点,该点表示左下角。为了建立从一边到另外一边的垂直填充(不倾斜),可使用点(0,0)做为开始点,并使用右上角的点(1,0)做为结束点。

  经过为渐变提供不是填充区域拐角点的开始点和结束点。可获得更灵活的渐变。例如,渐变可从点(0,0)拉伸到点(0,0.5),该点是左侧边缘上的中点。这会建立压缩的线性渐变——一种颜色从顶部开始,在中间混合到第二种颜色。形状的后半部分使用第二种颜色。但可用LinearGradientBrush.SpreadMethod属性改变这种行为。默认状况下,该属性使用Pad(这意味着渐变以外的区域使用恰当的纯色填充),但也可以使用Reflect(翻转渐变,从第二种颜色反向渐变大偶第一种颜色)或Repeat(复制相同的颜色变化过程)。

  LinearGradientBrush画刷还可经过添加两个以上的GradientStop对象,建立具备两种以上的颜色渐变。例如,下面的渐变实现了彩虹效果:

<Rectangle Width="150" Height="100" Grid.Row="4" Margin="5">
            <Rectangle.Fill>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

  惟一的技巧是为每一个GradientStop对象何止合适的偏移值。例如,若是但愿变换通过5中颜色,可将第1中颜色的偏移值设置为0,第2中颜色的偏移值设置为0.25,将第3中颜色的偏移值设置为0.5,第4种颜色的偏移值设置为0.75,将第5中颜色的偏移值设置为1。或者若是但愿开始时渐变速度较快,而在结束速度较慢,可将便宜值设置为0、0.一、0.二、0.四、0.六、1。

  下面是LinearGradientBrush画刷的完整示例以及效果图:

<Window x:Class="Drawing.Gradients"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Gradients" Height="587" Width="347">
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <Rectangle Width="150" Height="100" Margin="5">
            <Rectangle.Fill>
                <LinearGradientBrush >
                    <GradientStop Color="Blue" Offset="0"/>
                    <GradientStop Color="White" Offset="1" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
        <TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="5">Diagonal Linear Gradient</TextBlock>

        <Rectangle Width="150" Height="100" Margin="5" Grid.Row="1">
            <Rectangle.Fill>
                <LinearGradientBrush>
                    <GradientStop Color="Blue" Offset="0"/>
                    <GradientStop Color="White" Offset="0.5" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
        <TextBlock Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Margin="5">With 0.5 Offset for White</TextBlock>

        <Rectangle Width="150" Height="100" Grid.Row="2" Margin="5">
            <Rectangle.Fill>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
                    <GradientStop Color="Blue" Offset="0"/>
                    <GradientStop Color="White" Offset="1" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
        <TextBlock Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" Margin="5">Horizontal Linear Gradient</TextBlock>

        <Rectangle Width="150" Height="100" Grid.Row="3" Margin="5">
            <Rectangle.Fill>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,0.5" SpreadMethod="Reflect">
                    <GradientStop Color="Blue" Offset="0"/>
                    <GradientStop Color="White" Offset="1" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
        <TextBlock Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" Margin="5">Reflected Gradient</TextBlock>

        <Rectangle Width="150" Height="100" Grid.Row="4" Margin="5">
            <Rectangle.Fill>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
        <TextBlock Grid.Row="4" Grid.Column="1" VerticalAlignment="Center" Margin="5">Multicolored Gradient</TextBlock>
    </Grid>
</Window>
Gradients

 

   渐变画刷并不限于绘制形状。可在使用SolidColorBrush画刷的任什么时候候替代LinearGradientBrush——例如,填充元素的背景表面(使用Background属性)、填充元素文本的前景色(使用Foreground属性)或者填充边框(使用BorderBrush属性)。以下示例所示:

<Window x:Class="Drawing.GradientText"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="GradientText" Height="300" Width="300">
    <Grid>
        <TextBlock Margin="5"  FontWeight="Bold" FontSize="65" TextWrapping="Wrap" TextAlignment="Center">
            <TextBlock.Text>This text uses a gradient.</TextBlock.Text>
            <TextBlock.Foreground>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
            </TextBlock.Foreground>
        </TextBlock>
    </Grid>
</Window>
GradientText

3、RadialGradientBrush画刷

  RadialGradientBrush画刷和LinearGradientBrush画刷的工做方式相似,也使用一系列具备不一样偏移值的颜色。与LinearGradientBrush画刷同样,可以使用但愿的任意多种颜色。区域是放置渐变的方式。

  为指定第一种颜色在渐变中的开始点,须要使用GradientOrigin属性。默认状况下,渐变的开始点是(0.5,0.5),该点表示填充区域的中心。

  渐变从开始点以环形的方式向外辐射。渐变最终到达内部渐变圆的边缘,这里是渐变的终点。根据所指望的效果,渐变圆的中心可能和渐变开始点对齐,也可能和渐变开始点不对齐。超出内部渐变圆的区域以及填充区域的最外侧边缘。使用在RadialGradientBrush.GradientStops集合中定义的最后一种颜色进行纯色填充。

  可以使用三个属性设置内部渐变圆的边界:Center、RadiusX和RadiusY。默认状况下,Center属性被设置为(0.5,0.5),该设置将限定圆的中心放在填充区域的中央,而且该点同时也是渐变开始点。

  RadiusX和RadiusY属性 决定了限定圆的尺寸,默认状况下着两个属性都被设置为0.5.这些值可能不够直观,由于他们根据填充区域的对角范围(一条从填充区域的左上角延伸到右下角的假想线的长度)进行度量。这意味着半径0.5定义了一个圆,该圆的半径是对角线长度的一半。若是填充区域为正方形,使用勾股定理可计算出,该长度大约是填充区域宽度(或宽度)的0.7倍。所以,若是用默认设置填充正方形区域,渐变就从中心点开始,并拉伸大约正方形宽度0.7倍的距离到达最外侧边界。

  对于填充圆形形状并建立发光效果,径向渐变是很是好的选择(水平高超的美工人员经过组合使用渐变建立具备光晕效果的按钮)。一种常见技巧是稍微偏移GradientOrigin点,为形状建立深度感。

<Window x:Class="Drawing.RadialGradient"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="RadialGradient" Height="534" Width="480">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Ellipse Margin="5" Stroke="Black" StrokeThickness="1">
            <Ellipse.Fill>
                <RadialGradientBrush RadiusX="1" RadiusY="1" >
                    <GradientStop Color="White" Offset="0"/>
                    <GradientStop Color="Blue" Offset="1"/>
                </RadialGradientBrush>
            </Ellipse.Fill>
        </Ellipse>
        <TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="5">A Radial Gradient</TextBlock>

        <Ellipse Margin="5" Grid.Row="1" Stroke="Black" StrokeThickness="1">
            <Ellipse.Fill>
                <RadialGradientBrush
             RadiusX="1" RadiusY="1" GradientOrigin="0.7,0.3"
            >
                    <GradientStop Color="White" Offset="0" />
                    <GradientStop Color="Blue" Offset="1" />
                </RadialGradientBrush>

            </Ellipse.Fill>
        </Ellipse>
        <TextBlock Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Margin="5" TextWrapping="Wrap">A Radial Gradient with an Offset Center</TextBlock>

    </Grid>
</Window>
RadialGradient

 

 4、ImageBrush画刷

  可经过ImageBrush画刷使用位图填充区域。可以使用最多见的文件类型,包括BMP、PNG、GIF以及JPEG文件。可经过设置ImageSource属性来制定但愿使用的图像。例如,下面的画刷使用一幅名为logo.jpg的图像绘制Grid面板的背景,在程序集中做为资源包含了该图像:

<Grid>
        <Grid.Background>
            <ImageBrush  ImageSource="logo.jpg" />
        </Grid.Background>    
    </Grid>

  ImageBrush.ImageSource属性和Image元素的Source属性的工做方式相同,这意味着也可使用指向资源、外部文件或Web站点的URI设置ImageSource属性。也可经过为ImageSource属性提供DrawingImage对象,建立使用由XAML定义的矢量内容的ImageBrush画刷。可经过这种方法下降开销(经过避免使用更耗资源的Shape类的派生类),或使用矢量图像建立平铺模式。

  在该例中,ImageBrush画刷用于绘制单元格的背景。所以,为了适应填充区域,图像会被拉伸。若是Grid面板比图像的原始尺寸大,就会看到改变图像尺寸形成的显示问题(如常见的模糊效果)。若是Grid面板的形状和图像的宽高比不匹配,为了适应Grid面板,图像会变形。

  为控制该行为,可修改ImageBrush.Stretch属性。例如,可将该属性设置为Uniform,从而为了适应缩放图像时保持图像的高宽比,或将该属性设置为None,使用图像的天然尺寸绘制图像(对于这种状况,为适应容器,部分图像可能被裁减掉)。

  若是绘制的图像比填充区域小,图像会根据AlignmentX和AlignmentY属性进行对齐。未填充的区域保持透明。当使用Uniform设置进行缩放,而且填充区域的形状不一样时,就会出现这种状况。若是将Stretch属性设置为None,而且填充区域比图像大,也会出现这种状况。

  还可以使用Viewbox属性从图像上裁剪有兴趣使用的一小部分。为此,须要指定4个数值以描述但愿从源图上裁剪并使用的矩形部分。前连个数值指定矩形开始的左上角,然后两个数值指定矩形的宽度和高度。惟一的问题是Viewbox属性使用的是相对坐标系统,就像渐变画刷使用的坐标系统那样。这一坐标系统将图像上的左上角指定为(0,0),将右下角指定为(1,1)。

  为理解Viewbox属性的工做原理,分析下面的标记:

<ImageBrush ImageSource="logo.jpg" Stretch="Uniform"
    Viewbox="0.4 0.5 0.2 0.2"></ImageBrush>

  如今,Viewbox属性从(0.4,0.5)开始,这差很少是用图像的一半出开始(从技术角度看,X坐标是宽度的0.4倍,Y坐标是高度的0.5倍)。而后伸展矩形以填充一个20%宽度和20%高度的小方块做为整幅图像(从技术角度看,矩形的长度为图像宽度的0.2倍,矩形的高度为图像高度的0.2倍)。根据Stretch、AlignmentX以及AlignmentY属性的设置,被裁剪下来的部分图像会被拉伸或剧中显示。下图显示两个使用不一样ImageBrush对象填充自身的矩形。最上面的矩形显示了整幅图像,下面的矩形使用Viewbox放大了图像中的一小部分。这两个矩形都使用了纯黑色的边框。

<Window x:Class="Drawing.ImageBrushes"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ImageBrushes" Height="389.6" Width="419.6">
    <Canvas>
        <Rectangle Canvas.Left="10" Canvas.Top="10"  Width="271" Height="100" Stroke="Black">
            <Rectangle.Fill>
                <ImageBrush ImageSource="logo.jpg" Stretch="Fill"></ImageBrush>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle Canvas.Left="10" Canvas.Top="120" Width="200" Height="200" Stroke="Black">
            <Rectangle.Fill>
                <ImageBrush ImageSource="logo.jpg" Stretch="Uniform"
    Viewbox="0.4 0.5 0.2 0.2"></ImageBrush>
            </Rectangle.Fill>
        </Rectangle>
    </Canvas>
</Window>
ImageBrushes

 

 5、平铺的ImageBrush画刷

  除广泛的ImageBrush画刷外,还有其余使人更加激动的内容。可经过在画刷的表面平铺图像来获得一些有趣的效果。

  当平铺图像时,有两种选择:

  •   按比例平铺。填充区域始终具备相同数量的平铺图像。为适应填充区域,平铺的图像会扩展或收缩。
  •   按固定尺寸平铺。平铺图像始终具备相同的尺寸。填充区域的尺寸决定了显示的平铺图像的数量。

  为了平铺一幅图像,须要设置ImageSource属性(指定但愿平铺的图像)以及ViewPort、ViewportUnits与TitleMode属性。后三个属性决定了平铺图像的尺寸和排列方式。

  可以使用Viewport属性设置每幅平铺图像的尺寸。为使用按比例平铺模式,必须将ViewportUnits属性这是为RelativeToBoundingBox(默认值)。而后使用在两个方向上的坐标范围都是从0到1的按比例坐标定义平铺图像的尺寸。换句话说,若是一幅平铺图像的左上角位于(0,0),右下角位于(1,1),就会占据整个填充区域。为获得平铺模式,为Viewport属性设置的值应当比整个填充区域的尺寸小。以下所示:

<ImageBrush ImageSource="tile.jpg" TileMode="Tile"
                     Viewport="0 0 0.5 0.5"></ImageBrush>

  上面的标记建立了一个从填充区域的左上角(0,0)开始,并拉伸到中间点(0.5,0.5)的Viewport方框。所以,无论填充区域的大小如何,填充区域始终包含4幅平铺图像。这样行为很是好,由于可确保平铺图像不会在形状的边缘被裁减(固然,若是使用ImageBrush画刷填充非矩形区域,图像仍会被裁剪)。

  由于这个示例中的平铺图像采用相对于填充区域的尺寸,因此更大的填充区域会使用更大的平铺图像,而且由于改变了图像的尺寸。因此会形成必定的模糊效果。此外,若是填充区域不是完美的正方形,相对坐标系统会相应地进行行挤压,从而每一个平铺的正方形都会变成矩形。

  可经过修改Stretch属性(默认设置为Fill)改变这种行为。若是将该属性设置为None,可保证平铺图像永不变形,而且保持正确的形状,然而,若是填充区域不是正方形,将在平铺图像之间显示空白空间。

  第三种选择是将Stretch属性设置为UniformToFill这种设置会根据须要裁减平铺的图像。使用这种方式,平铺图像会保持正确的纵横比,并且平铺的图像之间没有空白空间。然而,若是填充的区域不是正方形,就不会看到完整的平铺图像。

  自动改变平铺图像的尺寸是一项很是有用的功能,但也是须要付出代价。有些位图可能不能正确地改变其尺寸。在某种程度上,可经过提供比所需位图更大的位图,为应对这种状况作好准备。当当缩小图像时,这种技术就会致使更模糊的位图。

  另外一种定义平铺图像的尺寸的方法是根据原始图像的尺寸使用绝对坐标。为此,将ViewportUnits属性设置为Absolute。下面举一个示例,该例将每幅平铺图像定义为32X32单位大小,并从左上角开始平铺:

<ImageBrush ImageSource="tile.jpg" TileMode="Tile"
                            ViewboxUnits="Absolute" Viewbox="0 0 32 32"/>

  这种模式的缺点就是填充区域的高度和宽度必须能被32整除。不然,在填充区域便于就会显示部分平铺图像。若是使用ImageBrush画刷填充可改变尺寸的元素,就没法避免该问题,因此必须接受平铺图像未必能与填充区域的边缘对齐这种状况。

  下面是上面示例的完整XAML:

<Window x:Class="Drawing.TileTypes"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TileTypes" Height="500" Width="296.8">
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <TextBlock Margin="3">固定尺寸<LineBreak></LineBreak>平铺</TextBlock>
        <Rectangle Grid.Column="1" Stroke="Black">
            <Rectangle.Fill>
                <ImageBrush ImageSource="tile.jpg" TileMode="Tile"
                            ViewboxUnits="Absolute" Viewbox="0 0 32 32"/>
            </Rectangle.Fill>
        </Rectangle>

        <TextBlock Grid.Row="1" Margin="3">按比例<LineBreak></LineBreak>平铺</TextBlock>
        <Rectangle Grid.Row="1" Grid.Column="1" Stroke="Black">
            <Rectangle.Fill>
                <ImageBrush ImageSource="tile.jpg" TileMode="Tile"
                     Viewport="0 0 0.5 0.5"></ImageBrush>
            </Rectangle.Fill>
        </Rectangle>

        <TextBlock Grid.Row="2" Margin="3">
      按比例<LineBreak></LineBreak>平铺(无拉伸)
        </TextBlock>
        <Rectangle Grid.Row="2" Grid.Column="1" Stroke="Black">
            <Rectangle.Fill>
                <ImageBrush ImageSource="tile.jpg" TileMode="Tile" Stretch="None"
                    Viewport="0 0 0.5 0.5"></ImageBrush>
            </Rectangle.Fill>
        </Rectangle>
    </Grid>
</Window>
TileTypes

  下表列出了TileMode枚举值得全部选项.

表 TileMode枚举值

 

   若是须要 使平铺图像更无缝地混合,翻转行为一般是有用的。例如,若是使用FlipX,相邻的平铺图像总能够无缝地排列。下面举例说明一下。

<Window x:Class="Drawing.TileFlip"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TileFlip" Height="300" Width="300">
    <!-- Overlay labels by putting one UniformGrid on top of another. -->
    <Grid>
        <UniformGrid>
            <Rectangle Stroke="Black">
                <Rectangle.Fill>
                    <ImageBrush ImageSource="tile.jpg" TileMode="Tile" 
                    ViewportUnits="Absolute" Viewport="0 0 37 37"></ImageBrush>
                </Rectangle.Fill>
            </Rectangle>
            <Rectangle Stroke="Black">
                <Rectangle.Fill>
                    <ImageBrush ImageSource="tile.jpg" TileMode="FlipX"
                    ViewportUnits="Absolute" Viewport="0 0 37 37"></ImageBrush>
                </Rectangle.Fill>
            </Rectangle>
            <Rectangle Stroke="Black">
                <Rectangle.Fill>
                    <ImageBrush ImageSource="tile.jpg" TileMode="FlipY"
                    ViewportUnits="Absolute" Viewport="0 0 37 37"></ImageBrush>
                </Rectangle.Fill>
            </Rectangle>
            <Rectangle Stroke="Black">
                <Rectangle.Fill>
                    <ImageBrush ImageSource="tile.jpg" TileMode="FlipXY"
                    ViewportUnits="Absolute" Viewport="0 0 37 37"></ImageBrush>
                </Rectangle.Fill>
            </Rectangle>
        </UniformGrid>
        <UniformGrid>
            <UniformGrid.Resources>
                <Style TargetType="{x:Type TextBlock}">
                    <Setter Property="HorizontalAlignment" Value="Center"></Setter>
                    <Setter Property="VerticalAlignment" Value="Bottom"></Setter>
                    <Setter Property="FontSize" Value="25"></Setter>
                    <Setter Property="FontWeight" Value="Bold"></Setter>
                    <Setter Property="Margin" Value="3"></Setter>
                </Style>
            </UniformGrid.Resources>
            <TextBlock>Tile</TextBlock>
            <TextBlock>FlipX</TextBlock>
            <TextBlock>FlipY</TextBlock>
            <TextBlock>FlipXY</TextBlock>
        </UniformGrid>
    </Grid>
</Window>
TileFlip

 

 6、VisualBrush画刷

  VisualBrush画刷不经常使用,使用这种画刷获取元素的可视化内容,并使用该内容填充任意表面。例如,可以使用VisualBrush画刷将窗口中某个按钮的外观复制到同一个窗口中的其余位置。然而,复制的按钮不能被单击,也不能经过任何方式与其进行交互。在此就复制了元素的外观。例如,下面的标记片断定义了一个按钮和用于复制该按钮的VisualBrush画刷:

 <Button Name="cmd" Margin="3" Padding="5">Is this a real button?</Button>
        <Rectangle Margin="3" Height="{Binding ElementName=cmd,Path=ActualHeight}">
            <Rectangle.Fill>
                <VisualBrush Visual="{Binding ElementName=cmd}"></VisualBrush>
            </Rectangle.Fill>
</Rectangle>

  尽管可在VisualBrush自己定义但愿使用的元素,但一般使用绑定表达式引用当前窗口中的额元素。如本例所示,下图显示了原始按钮(在窗口顶部)和几个形状不一样的区域,这些区域是用基于按钮的VisualBrush画刷绘制的。完整XAML以下所示:

<Window x:Class="Drawing.VisualBrush"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="VisualBrush" Height="300" Width="300">
    <StackPanel Margin="3">
        <Button Name="cmd" Margin="3" Padding="5">Is this a real button?</Button>
        <Rectangle Margin="3" Height="{Binding ElementName=cmd,Path=ActualHeight}">
            <Rectangle.Fill>
                <VisualBrush Visual="{Binding ElementName=cmd}"></VisualBrush>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle Margin="3" Height="50">
            <Rectangle.Fill>
                <VisualBrush Visual="{Binding ElementName=cmd}"></VisualBrush>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle Margin="3" Height="150">
            <Rectangle.Fill>
                <VisualBrush Visual="{Binding ElementName=cmd}"></VisualBrush>
            </Rectangle.Fill>
        </Rectangle>
    </StackPanel>
</Window>
VisualBrush

 

   VisualBrush监视元素外观的变化。例如,若是复制某个按钮的可视化外观,并且此外按钮收到焦点,VisualBrush画刷会使用新的可视化内容从新绘制填充区域——一个具备焦点的按钮。VisualBrush类继承自TileBrush类,所以,VisualBrush类也支持全部的裁剪、拉伸以及翻转等特性。

7、BitmapCacheBrush画刷

  BitmapCacheBrush画刷在许多方面和VisualBrush画刷相似。尽管VisualBrush类提供了用于引用其余元素的Visual属性,但BitmapCacheBrush类提供了与此做用相同的Target属性。

  二者之间的关键区别是,BitmapCacheBrush画刷采用可视化内容(这些内容以及经过变换、裁剪、效果以及透明设置进行了改变)并要求显卡在显存中存储该内容。这样一来,当须要时可快速地从新绘制内容,而没必要要求WPF执行任何额外的工做。

  为配置位图缓存,设置BitmapCacheBrush.BitmapCache属性(使用可预先肯定的BitmapCache对象)。下面是最简单的用法:

<Button Name="cmd" Margin="3" Padding="5">Is this a real button?</Button>
        <Rectangle Margin="3" Height="{Binding ElementName=cmd,Path=ActualHeight}">
            <Rectangle.Fill>
                <BitmapCacheBrush Target="{Binding ElementName=cmd}">
                </BitmapCacheBrush>
            </Rectangle.Fill>
        </Rectangle>

  BitmapCacheBrush画刷存在严重缺点:渲染位图以及将其复制到显存的初始化步骤须要比较短但可察觉到得额外时间。若是在窗口中使用BitmapCacheBrush画刷,在窗口第一次绘制自身以前,当渲染BitmapCacheBrush并复制其位图时,将会注意到延迟。所以,在传统窗口中,BitmapCacheBrush起不到多大的帮助做用。

  然而,若是在用户界面中大量使用动画,值得考虑使用位图缓存。这是由于动画会强制窗口在没一秒内从新绘制屡次。若是具备复杂的矢量内容,从缓存位图中绘制窗口内容比从头从新绘制窗口要快。但即便是这种状况,也不该当当即使用BitmapCacheBrush画刷。可能更愿意经过为每一个但愿缓存的元素设置更高级的UIElement.CacheMode属性来应用缓存。对于这种状况,WPF在后台使用BitmapCacheBrush画刷获取相同的效果,但须要作的工做更少。

  根据这些细节,BitmapCacheBrush画刷自己好像不是颇有用。然而,若是须要在几个地方绘制单块复杂的可视化内容,使用BitmapCacheBrush画刷是合理的。对于这种状况,经过使用BitmapCacheBrush画刷缓存整个可视化内容比单独缓存每一个元素更节省内存。在此输出,这种节省可能得不偿失,除非用户界面还使用了动画。

相关文章
相关标签/搜索