畫刷填充區域,不管是元素的背景色、前景色以及邊框,還是形狀的內部填充和筆畫(Stroke)。最簡單的畫刷類型是SolidColorBrush,這種畫刷填充一種固定、連續的顏色。在XAML中設置形狀的Stroke或Fill屬性時,使用的是SolidColorBrush畫刷,他們在後臺完成繪製。 下麵是 ...
畫刷填充區域,不管是元素的背景色、前景色以及邊框,還是形狀的內部填充和筆畫(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