前面簡單的說到了wpf中幾種樣式的用法,wpf有着類似web中的CSS一樣,為界面上的元素定制外觀,以提供更好的用戶界面,這種靈活性也是winForm所不能及的,從前面講到的可以知道在WPF應用程序中,通過控件的屬性,我們也可以實現更改控件的外觀。但是,這種方式局限性大、不靈活且不利於維護,比如一個,二個按鈕的樣式可以這樣,如果有二十,三十個,甚至更多,難道也這樣嗎,顯然這不是很好的選擇,如果我們將上述控件的屬性歸納起來,寫到一段樣式中,為按鈕指定該樣式(甚至用元素類型樣式時,都不需要指定按鈕樣式),所有按鈕就具有統一樣式和外觀了。如果想修改按鈕外觀,我們只需要改一下樣式代碼即可,所有按鈕外觀都會隨之變化。
樣式的使用有多種方法,如內聯樣式(定義在元素內部)、已命名樣式(為樣式命名,使用時通過名稱引用)、元素類型樣式(為一種類型的元素,指定一種樣式)等等。
一、內聯樣式
比如下面的為textBox加樣式
<TextBox Text="內容"> <TextBox.Style> <Style> <Setter Property="TextBox.FontSize" Value="16"></Setter> <Setter Property="TextBox.Width" Value="80"></Setter> <Setter Property="TextBox.Height" Value="40"></Setter> </Style> </TextBox.Style> </TextBox>
就是說,我們可以通過在元素內部通過拓展屬性Style來定義樣式。但是缺點也是顯而易見的,如果有多個這樣的控件指向同一個樣式,該怎么辦呢,只能每個都要寫,所以很不好,所以我們可以在資源中定義一個樣式,然后讓多個控件調用這一個樣式即可
二、已命名樣式
將相同的內斂樣式歸納起來,放入資源中,構成一個樣式,並為它起一個名字。這樣,就可以通過名字為元素指定該樣式。
<Window.Resources> <Style x:Key="buttonStyle"> <Setter Property="Foreground" Value="#999999"/> </Style> </Window.Resources>
然后調用即可
<Button Content="Button" Height="23" Style="{StaticResource buttonStyle}"
HorizontalAlignment="Left" Margin="10,204,0,0" Name="button5" VerticalAlignment="Top" Width="75" />
如果給樣式指定一種類型,則屬性中的名字可以去掉,加上指定目標類型(TargetType)
<Window.Resources> <Style x:Key="buttonStyle" TargetType="{x:Type Button}"> <Setter Property="Foreground" Value="#999999"/> </Style> </Window.Resources>
上述中的TargetType可以改成Control ,因為Button是從Control派生而來的。
如果其他控件也是派生自Control可以將Style1指定給這些控件也是合適的。這樣就能使多種元素共用一種樣式。
如:
<Window.Resources> <Style x:Key="Style1" TargetType="{x:Type Control }"> <Setter Property="FontSize" Value="16"></Setter> <Setter Property="Width" Value="180"></Setter> <Setter Property="Height" Value="30"> </Setter> </Style> </Window.Resources> <Grid> <Button Style="{StaticResource Style1}" Margin="23,32,95,139">Button1</Button> <CheckBox Style="{StaticResource Style1}" Margin="23,130,95,41">Checkbox1</CheckBox> </Grid>
Button、Check可以使用Style1,而TextBlock則不行,原因是TextBlock不是派生自Control。
重用樣式(Reusing Styles)
重用樣式指的是,樣式可以擁有目標所沒有的屬性。比如,我們想定義一種樣式,其中含有不想被所有元素共享的屬性,而只希望這些非共享屬性應用到特定的元素上。這時,我們就可以去掉目標類型,重新加上前綴。
<Window.Resources> <Style x:Key="Style1"> <Setter Property="CheckBox.FontSize" Value="16"></Setter> <Setter Property="Button.Foreground" Value="Red"></Setter> <Setter Property="CheckBox.IsChecked" Value="True"></Setter> </Style> </Window.Resources> <Grid> <CheckBox Style="{StaticResource Style1}" Margin="23,32,95,139">Button1</CheckBox> <TextBlock Style="{StaticResource Style1}">TextBlock1</TextBlock> </Grid>
將Style1同時指定給CheckBox1和TextBlock1,TextBlocak會自動忽略不適用它們自身的樣式屬性IsChecked。而二者公有的屬性(比如Foreground、FontSize),不論加不加前綴,對二者都有效。
重寫樣式(Overriding Style)
重寫樣式屬性類似於面向對象中的重寫,其效果也類似於CSS中的樣式覆蓋。最終的外觀取決於最近的樣式或者屬性。比如,給一個元素指定了一個樣式,其中包含FontSize屬性值為14。而在元素定義時,重新給它的屬性FontSize設置了一個值18。最終元素文本的FontSize將為18。
<Window.Resources> <Style x:Key="Style1"> <Setter Property="Button.FontSize" Value="14"></Setter> </Style> </Window.Resources> <Grid> <Button Width="80" Height="30" FontSize="18">Button1</Button> </Grid>
拓展樣式(Extending Styles)
可以對現有樣式進行拓展,類似於面向對象中的繼承或派生,可以在添加新的屬性或者重載已存在的屬性。
<Window.Resources> <Style x:Key="Style1" TargetType="Button"> <Setter Property="FontSize" Value="16"></Setter>
<Setter Property="Foreground" Value="Red"></Setter> </Style> <Style x:Key="Style2" BasedOn="{StaticResource Style1}" TargetType="Button"> <!--添加新屬性--> <Setter Property="FontWeight" Value="Bold"></Setter> <!--重載--> <Setter Property="Foreground" Value="Yellow"></Setter>
</Style> </Window.Resources> <Grid> <Button Style="{StaticResource Style1}" Width="80" Height="30" FontSize="18" Margin="109,55,109,116">Button1</Button>
<Button Style="{StaticResource Style2}" Width="80" Height="30" FontSize="18" Margin="109,120,109,51">Button2</Button>
</Grid>
三、元素類型樣式
一般來說,我們希望用戶界面上的控件擁有統一外觀,比如所有按鈕大小相同、顏色一致等,這時我們可以定義一種元素的樣式,對一個范圍內的所有元素都有效,這就是元素類型樣式。
同一類型元素共享外觀
倘若希望一個頂級窗口內所有的元素,具有相同的樣式和外觀——可以這樣實現:1.在頂級窗口資源中定義一個樣式,不標記x:Key,將TargetType設置為一種元素類型。2.定義元素,不用指定Style,窗口中所有該類型的元素,都將使用資源中定義的樣式,並具有統一外觀。
<Window.Resources> <!--Button 樣式--> <Style TargetType="{x:Type Button}"> <Setter Property="FontWeight" Value="Normal"></Setter> <Setter Property="Foreground" Value="Green"></Setter>
</Style> <!--TextBlock 樣式--> <Style TargetType="TextBlock"> <Setter Property="FontSize" Value="16"></Setter>
<Setter Property="Foreground" Value="Red"></Setter>
</Style>
</Window.Resources>
<Grid> <Button Name="Button1" Width="80" Height="30" Margin="46,41,172,130">Button1</Button> <Button Name="Button2" Width="80" Height="30" Margin="46,90,172,80">Button2</Button> <TextBlock Name="TextBlock1" Margin="164,41,38,0" Height="30" VerticalAlignment="Top">TextBlock1</TextBlock>
<TextBlock Name="TextBlock2" Margin="164,90,38,80">TextBlock2</TextBlock> </Grid>
作用范圍
以上的共享外觀不僅僅局限於頂級窗口,而是根據你定義的樣式所在的范圍。如果你將樣式定義在一個面板資源中,共享外觀將僅僅作用該面板。
窗口范圍(作用於該窗口)
<Window ...> <Window.Resources> <!--Button 樣式--> <Style TargetType="{x:Type Button}"> <Setter Property="Foreground" Value="Green"></Setter> </Style> </Window.Resources> </Window>
面板范圍(作用於該面板)
<Grid> <Grid.Resources> <!--Button 樣式--> <Style TargetType="{x:Type Button}"> <Setter Property="Foreground" Value="Green"></Setter> </Style> </Grid.Resources> <!----> </Grid>
應用程序范圍(作用於該應用程序)
<Application ...> <Application.Resources> <!--Button 樣式--> <Style TargetType="{x:Type Button}"> <Setter Property="Foreground" Value="Green"> </Setter> </Style> </Application.Resources> </Application>
四、編程控制樣式
通過代碼更改按鈕Button1的樣式:
<Window.Resources> <!--Style1--> <Style x:Key="Style1" TargetType="{x:Type Button}"> <Setter Property="FontWeight" Value="Normal"></Setter> <Setter Property="Foreground" Value="Green"></Setter> </Style> <!--Style2--> <Style x:Key="Style2" TargetType="{x:Type Button}"> <Setter Property="FontWeight" Value="Bold"></Setter> <Setter Property="Foreground" Value="Red"></Setter> </Style> </Window.Resources> <Grid> <Button Name="Button1" Width="100" Height="40" Style="{StaticResource Style1}">Button</Button> <Button Name="Button2" Width="150" Height="30" Click="Button2_Click" Margin="79,143,69,28">Change Button1's Style</Button> </Grid>
private void Button2_Click(object sender, RoutedEventArgs e)
{
this.Button1.Style = (Style)FindResource("Style2");
}
五、觸發器
樣式(Styles)由三部分構成:設置器(Setter)、觸發器(Triggers)、資源(Resources)。觸發器,讓樣式的使用更加准確、靈活和高效。觸發器(Triggers)主要分為三類,屬性觸發器(檢查從屬屬性即WPF元素自身屬性)、數據觸發器(檢查任意可綁定的屬性)、事件觸發器(用於監聽事件)。
屬性觸發器
檢查從屬屬性的值,即WPF元素自身屬性。比如按鈕的內容、字體的大小、顏色等等。
<Window.Resources> <Style TargetType="Button"> <Style.Triggers> <Trigger Property="Content" Value="按鈕"><Button Content="按鈕" Height="23" HorizontalAlignment="Left" Margin="28,6,0,0" Name="button1" VerticalAlignment="Top" Width="102" />
<Setter Property="ToolTip" Value="這是一個按鈕"> </Setter> </Trigger> </Style.Triggers> </Style> </Window.Resources>
注意的是: <Trigger Property="Content" Value="按鈕"> 一定要和<Button Content="按鈕".. content的值一樣,否則掉不出來
多屬性觸發器
<Window.Resources> <Style TargetType="Button"> <Style.Triggers> <Trigger Property="Content" Value="按鈕">
<Setter Property="ToolTip" Value="這是一個按鈕"></Setter> </Trigger> <Trigger Property="Content" Value="Button">
<Setter Property="ToolTip" Value="This is a button"></Setter> </Trigger> </Style.Triggers> </Style> </Window.Resources>
多條件屬性觸發器
<Window.Resources> <Style TargetType="Button"> <Style.Triggers> <MultiTrigger> <!--條件列表--> <MultiTrigger.Conditions> <Condition Property="Content" Value="按鈕"></Condition> <Condition Property="Visibility" Value="Visible"></Condition> </MultiTrigger.Conditions> <!--樣式--> <Setter Property="ToolTip" Value="這是一個可見按鈕"></Setter> </MultiTrigger> </Style.Triggers> </Style> </Window.Resources>
數據觸發器
可以檢查任意可綁定的屬性,比如CLR對象屬性、XPath聲明等。相對於屬性觸發器,數據觸發器通常用來檢查不可見的對象屬性。
<Window x:Class="WpfApplication2.樣式的用法.styleDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="styleDemo" Height="300" Width="300"> <Window.Resources> <Style TargetType="Button"> <Style.Triggers> <DataTrigger Binding="{Binding Path=Name}" Value="dd"> <Setter Property="Foreground" Value="Tomato"/> </DataTrigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Button Content="{Binding Path=Name}" Height="23" Margin="103,94,120,84" Name="button1" Width="75"/> </Grid> </Window>
public partial class styleDemo : Window { public styleDemo() { InitializeComponent(); DataContext = new Person("dddd", "dd"); } class Person { string _Name; public string Name { get { return _Name; } set { _Name = value; } } string _Age; public string Age { get { return _Age; } set { _Age = value; } } public Person(string name, string age) { _Name = name; _Age = age; } } }
多條件數據觸發器
<Window.Resources> <Style TargetType="Button"> <Style.Triggers> <MultiDataTrigger> <!--條件列表--> <MultiDataTrigger.Conditions> <Condition Binding="{Binding Path=Name}" Value="李寶亨"/> <Condition Binding="{Binding Path=Age}" Value="21"/> </MultiDataTrigger.Conditions> <Setter Property="Foreground" Value="Tomato"/> </MultiDataTrigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Button Content="{Binding Path=Name}" Height="23" Margin="103,94,120,84" Name="button1" Width="75"/> </Grid>
事件觸發器
<Window.Resources> <Style TargetType="Button"> <Style.Triggers> <!--事件觸發器--> <EventTrigger RoutedEvent="MouseEnter"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0.1" Duration="0:0:3"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Style.Triggers> </Style> </Window.Resources>
后續..