【WPF學習】第四十章 畫刷
畫刷填充區域,不管是元素的背景色、前景色以及邊框,還是形狀的內部填充和筆畫(Stroke)。最簡單的畫刷型別是SolidColorBrush,這種畫刷填充一種固定、連續的顏色。在XAML中設定形狀的Stroke或Fill屬性時,使用的是SolidColorBrush畫刷,他們在後臺完成繪製。
下面是幾個與畫刷相關的更基本的方面:
- 畫刷支援更改通知,因為他們繼承自Freezable類。因此,如果改變了畫刷,任何使用畫刷的元素都會自動重新繪製自身。
- 畫刷支援部分透明。為此,只需要修改Opacity屬性,使背景能夠透過前面的內容進行顯示。
- 通過SystemBrushes類可以訪問這樣的畫刷:此類畫刷使用Windows系統設定為當前計算機定義的首選顏色。
SolidColorBrush畫刷無疑非常有用,但還有其他幾個繼承自System.Windows.Media.Brush的類,通過這些類可得到更新穎的效果。下表列出了所有這些類。
表 畫刷類
一、SolidColorBrush畫刷
在大多數控制元件中,通過設定Foreground屬性繪製文字顏色,並設定Background屬性繪製文字背後的空間。形狀使用類似但不同的屬性:Stroke屬性用於繪製形狀的邊框,而Fill屬性用於繪製形狀的內部。
可在XAML中使用顏色名設定Stroke和Fill屬性,對於這種情況,WPF解析器自動建立匹配的SolidColorBrush物件。也可以使用程式碼設定Stroke和Fill屬性,但需要顯示地建立SolidColorBrush物件。
//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));
二、LinearGradientBrush畫刷
可通過LinearGradientBrush畫刷建立從一種顏色變化到另一種顏色的混合填充。
下面可能是最簡單的漸變。該漸變從藍色(左上角)到白色(右下角)在對角線上對矩形進行著色。
<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.1、0.2、0.4、0.6、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
三、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
四、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
五、平鋪的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
六、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類也支援所有的裁剪、拉伸以及翻轉等特性。
七、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畫刷快取整個視覺化內容比單獨快取每個元素更節省記憶體。在此輸出,這種節省可能得不償失,除非使用者介面還使用了動畫。
&n