說起樣式,大家第一反應肯定是css,好的,先上一段代碼。
1 html{border:0;} 2 ul,form{margin:0; padding:0} 3 body,div,th,td,li,dd,span,p,a{font-size:12px; font-family:Verdana,Arial,"宋體";color:#575757;} 4 h3,input{font-size:12px; font-family:Verdana,Arial,"宋體";color:#4465a2;} 5 6 body { 7 /*background-color:#eaeaea;*/ 8 /*e5e5e5*/ 9 /*BACKGROUND: url(../images/header_bg.jpg) #fff repeat-x;*/ 10 BACKGROUND: url(../images/color_1.png) #fff repeat-x 0px -233px; 11 margin:0px; 12 padding:0px; 13 } 14 15 ul{list-style:none;} 16 h1,h2,h4,h5,h6{ font-size:14px; color:#333;} 17 img{border:0;} 18 a {color:#333333;text-decoration:none;} 19 a:hover{color:#ff0000;text-decoration:underline;}
我們知道css實現了內容與樣式的分離,既然wpf跟webform非常類似,那么肯定也有一套能夠實現css的功能,是的。這就是wpf的style。
一:Style類
首先我們看看Style里面有哪些東西,在vs里面我們可以通過按F12查看類的定義。
下面我們一一解讀下:
1:Setters
從上圖我們知道Setters的類型是SetterBaseCollection,可以看得出是一個存放SetterBase的集合,SetterBase派生出了兩個類
Setter和EventSetter,下面我們看看Setter類的定義。
這里我們看到了兩個非常重要KV屬性Property和Value,我們拿css找找對應關系。
html{border:0;}
html => Style.TargetType
border => Property
0 => Value
估計大家想迫不及待的試一試,好了,我先做一個簡單的demo。
1 <Window x:Class="WpfApplication1.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:sys="clr-namespace:System;assembly=mscorlib" 5 Title="MainWindow" Height="350" Width="525"> 6 <Window.Resources> 7 <Style TargetType="Button"> 8 <Setter Property="Background" Value="Pink"/> 9 <Setter Property="FontSize" Value="22"/> 10 </Style> 11 </Window.Resources> 12 <Grid> 13 <Button Content="一線碼農"/> 14 </Grid> 15 </Window>
最后效果:
仔細看看,是不是找到了css的感覺,有人肯定要問,這不就是標簽選擇器嗎?能不能做成“id選擇器”,當然可以,我們只需要給style取一個名字,
然后在控件上引用一下就ok了。
1 <Window x:Class="WpfApplication1.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:sys="clr-namespace:System;assembly=mscorlib" 5 Title="MainWindow" Height="350" Width="525"> 6 <Window.Resources> 7 <Style x:Key="mystyle" TargetType="Button"> 8 <Setter Property="Background" Value="Pink"/> 9 <Setter Property="FontSize" Value="22"/> 10 </Style> 11 </Window.Resources> 12 <Grid> 13 <Button Style="{StaticResource ResourceKey=mystyle}" Content="一線碼農"/> 14 </Grid> 15 </Window>
現在我們添加一個label,如果我們也需要同樣的“背景色”和“字體”,那么我們是否要重新寫一個label的樣式嗎?答案肯定是否定的,聰明的你肯定會
想到”基類“。我們發現label和button都是繼承自ContentControl,都屬於內容控件,那么何不在TargetType中定義為ContentControl不就ok了嗎?
1 <Window x:Class="WpfApplication1.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:sys="clr-namespace:System;assembly=mscorlib" 5 Title="MainWindow" Height="350" Width="525"> 6 <Window.Resources> 7 <Style x:Key="mystyle" TargetType="ContentControl"> 8 <Setter Property="Background" Value="Pink"/> 9 <Setter Property="FontSize" Value="22"/> 10 </Style> 11 </Window.Resources> 12 <Grid> 13 <Button Style="{StaticResource ResourceKey=mystyle}" 14 Content="Button" Height="23" Margin="132,99,0,0" Name="button1" Width="75" /> 15 <Label Style="{StaticResource ResourceKey=mystyle}" 16 Content="Label" Height="28" Margin="140,168,0,0" Name="label1" /> 17 </Grid> 18 </Window>
2:TargetType
我們在說Setter的時候也提到了,其實TargetType也就是將樣式施加到某一個對象上,具體的也沒什么好說的。
3:BaseOn
我們知道css具有“繼承和覆蓋”的特性,同樣我們的wpf中也是具有的。
<1>:繼承
1 <Window x:Class="WpfApplication1.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:sys="clr-namespace:System;assembly=mscorlib" 5 Title="MainWindow" Height="350" Width="525"> 6 <Window.Resources> 7 <Style x:Key="baseStyle" TargetType="Button"> 8 <Setter Property="FontSize" Value="22"/> 9 </Style> 10 <Style x:Key="childStyle" TargetType="Button" 11 BasedOn="{StaticResource ResourceKey=baseStyle}"> 12 <Setter Property="Background" Value="Pink"/> 13 </Style> 14 </Window.Resources> 15 <Grid> 16 <Button Style="{StaticResource ResourceKey=childStyle}" Content="一線碼農"/> 17 </Grid> 18 </Window>
效果:
從上例中,我們看到childStyle繼承到了baseStyle中的fontSize,最終的效果也是我們期望看到的。
<2>:覆蓋
我們知道css遵循“就近原則”。
①:“行內”覆蓋“嵌入”,“嵌入”覆蓋“外部”
我們可以清楚的看到,行內樣式覆蓋了嵌入樣式。
②:同級別遵循“就近”。
從button的顏色上看,我們可以獲知Pink已經被BurlyWood覆蓋。
4:Triggers
顧名思義,是觸發器的意思,我們可以認為是wpf在style中注入了一些很簡單,很sb的js代碼。
wpf中有5種trigger,都是繼承自TriggerBase類。
<1> Trigger,MuliTrigger
我們知道js是事件驅動機制的,比如觸發mouseover,mouseout,click等事件來滿足我們要處理的邏輯,那么wpf在不用寫C#代碼的情況下
用trigger就能夠簡單的滿足這些事件處理。
下面舉個例子
1 <Window x:Class="WpfApplication1.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:sys="clr-namespace:System;assembly=mscorlib" 5 Title="MainWindow" Height="350" Width="525"> 6 <Window.Resources> 7 <Style x:Key="childStyle" TargetType="Button"> 8 <Setter Property="Background" Value="BurlyWood"/> 9 <Style.Triggers> 10 <!-- 當IsMouseOver的時候,Button顏色變成粉色 --> 11 <Trigger Property="IsMouseOver" Value="True"> 12 <Setter Property="Background" Value="Pink"/> 13 </Trigger> 14 </Style.Triggers> 15 </Style> 16 </Window.Resources> 17 <Grid> 18 <Button Style="{StaticResource ResourceKey=childStyle}" Content="一線碼農"> 19 </Button> 20 </Grid> 21 </Window>
最后的效果就是當isMouseOver=true的情況下,button的Background變成Pink。
然而trigger只能滿足在單一的條件下觸發,那么我想在多個條件同時滿足的情況下才能觸發有沒有辦法做到呢?剛好MuliTrigger就可以幫你實現。
1 <Window x:Class="WpfApplication1.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:sys="clr-namespace:System;assembly=mscorlib" 5 Title="MainWindow" Height="350" Width="525"> 6 <Window.Resources> 7 <Style x:Key="childStyle" TargetType="Button"> 8 <Setter Property="Background" Value="BurlyWood"/> 9 <Style.Triggers> 10 <MultiTrigger> 11 <MultiTrigger.Conditions> 12 <Condition Property="IsMouseOver" Value="True"></Condition> 13 <Condition Property="IsPressed" Value="True"></Condition> 14 </MultiTrigger.Conditions> 15 <Setter Property="Background" Value="Pink"/> 16 </MultiTrigger> 17 </Style.Triggers> 18 </Style> 19 </Window.Resources> 20 <Grid> 21 <Button Style="{StaticResource ResourceKey=childStyle}" Content="一線碼農"> 22 </Button> 23 </Grid> 24 </Window>
這里我們看到,只有滿足了ismouseover和ispressed的時候,我們的button才會變成粉色。
<2>DataTrigger,MultiDataTrigger
這個跟上面的Trigger有什么不同呢?其實也就是DataTrigger多了一個Binding的屬性,當然它的實際應用也是最廣泛的。
1 <Window x:Class="WpfApplication1.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:sys="clr-namespace:System;assembly=mscorlib" 5 Title="MainWindow" Height="350" Width="525"> 6 <Window.Resources> 7 <Style x:Key="childStyle" TargetType="Control"> 8 <Setter Property="Background" Value="BurlyWood"/> 9 <Style.Triggers> 10 <!-- 綁定當前的radio單選框,如果按鈕選中,觸發字體設置 --> 11 <DataTrigger Binding="{Binding ElementName=radio, Path=IsChecked}" Value="True"> 12 <Setter Property="FontSize" Value="20"/> 13 </DataTrigger> 14 </Style.Triggers> 15 </Style> 16 </Window.Resources> 17 <Grid> 18 <RadioButton Style="{StaticResource ResourceKey=childStyle}" 19 Name="radio" Content="我要變成20號字"></RadioButton> 20 </Grid> 21 </Window>
效果:
=>
當我們選中radio的時候,字體變大,同樣MultiDataTrigger這個多條件的使用道理也是一樣的,這里就不介紹了。
<3>EventTrigger
這個trigger與動畫有關,目前項目中還沒接觸到,留給大家自己研究研究。
5:IsSealed
用於標記style是只讀的,類似我們在C#中的Seal關鍵字,來達到不允許讓繼承類使用,wpf使用seal常常在C#代碼里面控制,在xaml中我們
是找不到的,有興趣的話,大家自己研究研究。