Windows Phone開發(16):樣式和控件模板

在前面資源一文中也提過樣式,樣式就如同我們做HTML頁排版時常用到的CSS樣式表,它是對於特定婁型的可視化元素,應該可以直接說是針對控件的一種可重用的屬性設置列表,這樣對於需要設置相同屬性值的同類型的多個控件來講是大大提高效率,我們不必要爲每個控件做重複的動作。
下面是一個TextBox的樣式示例,我們希望通過引用資源中的樣式,使得頁面上的所有TextBox控件都具有統一的外觀,而且都只能輸入數字。

  1. <phone:PhoneApplicationPage.Resources>  
  2.     <!--不帶key的樣式,應用於所有TextBlock元素-->  
  3.     <Style TargetType="TextBlock">  
  4.         <Setter Property="FontSize" Value="40"/>  
  5.         <Setter Property="Foreground" Value="Yellow"/>  
  6.     </Style>   
  7.     <!--帶key的樣式,只有引用該資源的元素才應用-->  
  8.     <Style x:Key="MyTextBoxStyle" TargetType="TextBox">  
  9.         <Setter Property="FontSize" Value="40"/>  
  10.         <Setter Property="Foreground" Value="Blue"/>  
  11.         <Setter Property="InputScope">  
  12.             <Setter.Value>  
  13.                 <InputScope>  
  14.                     <InputScopeName NameValue="Number"/>  
  15.                 </InputScope>  
  16.             </Setter.Value>  
  17.         </Setter>  
  18.     </Style>  
  19. </phone:PhoneApplicationPage.Resources>  
  20.     <Grid x:Name="LayoutRoot" Background="Transparent">  
  21.     <Grid.RowDefinitions>  
  22.         <RowDefinition Height="Auto"/>  
  23.         <RowDefinition Height="*"/>  
  24.     </Grid.RowDefinitions>  
  25.   
  26.         <TextBlock Grid.Row="0" x:Name="PageTitle" Text="樣式示例" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>  
  27.   
  28.     <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,10,12,0">  
  29.         <Grid.RowDefinitions>  
  30.             <RowDefinition Height="auto"/>  
  31.             <RowDefinition Height="auto"/>  
  32.             <RowDefinition Height="auto"/>  
  33.             <RowDefinition Height="auto"/>  
  34.             <RowDefinition Height="auto"/>  
  35.         </Grid.RowDefinitions>  
  36.         <Grid.ColumnDefinitions>  
  37.             <ColumnDefinition Width="2*"/>  
  38.             <ColumnDefinition Width="3*"/>  
  39.         </Grid.ColumnDefinitions>  
  40.         <TextBlock Grid.Column="0" Grid.Row="0" Text="文本一:"/>  
  41.         <TextBlock Grid.Column="0" Grid.Row="1" Text="文本二:"/>  
  42.         <TextBlock Grid.Column="0" Grid.Row="2" Text="文本三:"/>  
  43.         <TextBlock Grid.Column="0" Grid.Row="3" Text="文本四:"/>  
  44.         <TextBlock Grid.Column="0" Grid.Row="4" Text="文本五:"/>  
  45.           
  46.         <TextBox Grid.Column="1" Grid.Row="0" Style="{StaticResource MyTextBoxStyle}" />  
  47.         <TextBox Grid.Column="1" Grid.Row="1" Style="{StaticResource MyTextBoxStyle}" />  
  48.         <TextBox Grid.Column="1" Grid.Row="2" Style="{StaticResource MyTextBoxStyle}" />  
  49.         <TextBox Grid.Column="1" Grid.Row="3"/>  
  50.         <TextBox Grid.Column="1" Grid.Row="4"/>  
  51.     </Grid>  
  52. </Grid>  


 

樣式在資源中有兩種聲明方式,一種是帶鍵值,一種是不帶鍵值的。
1、帶key的樣式,不會自動應用到元素/控件上,除非元素的Style屬性引用了該資源的鍵;
2、不帶鍵的樣式資源,將自動應用於當前頁面(如果資源聲明在當前頁)中的所有同類型的元素。
所以,在上例中,你會看到左邊的一列TextBlock,它們都沒有顯式設置Style屬性,但它們都一致引用了第一個樣式,因爲該樣式是不帶鍵的。
而右面的一列TextBox,由於後面兩個沒有顯式設置Style屬性,故它們保持默認樣式。

 

 

 

控件模板並不常用,除非你對控件的外觀的行爲特效有較高的要求,因爲我們不能把控的外觀弄得太花了,這樣反而降低用戶體驗,簡潔明瞭的東西其實是讓人看的最舒服的。
要自定義控件模板,首先要了解一下狀態。
如果你以前做過WPF開發你會知道,在.NET 3.5的時候,自定義控件模板,針對控件狀態的改變所做出的應對策略是通過觸發器來完成的,但到了.NET 4,就有了狀態的概念,而Silverlight 3也引入這概念,這樣使得控件的狀態管理更方便也更靈活了。
還有一點就是狀態有分組的,每個組裏面的狀態是互斥的,也就是不能同時發生,每個時刻只允許組內一個狀態發生,但不同組之間的狀態是不衝突的。
瞭解了狀態後,還有一概念,就是部件,這個好理解了,比如我們要組裝一輛汽車,需要哪些部件,輪胎放哪個位置,車門怎麼放置等。對於複雜的控件,有可以有N個控件或UI元素組成,由於WPF是把UI和代碼邏輯完全分開的,但有些時候我們也希望與UI元素進行交互,如某UI元素是否透明,是否被移動了,或者模板中的按鈕可能要觸發其單擊事件等,爲了方便後臺代碼能夠找到這些部件,所以在控件開發的時候會爲這些特定部件統一命名。
那麼,怎麼知道一個控件的模板中有哪些狀態,有哪些特定的部件呢?從控件類的定義所附加的Attribute特性來獲取,如,Button控件的狀態和部個有:

 

 

  1. // 摘要:  
  2. //     表示按鈕控件。  
  3. [TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]  
  4. [TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]  
  5. [TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]  
  6. [TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")]  
  7. [TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]  
  8. [TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]  
  9. public class Button : ButtonBase  


 

Button控件是內容控件,它並不複雜,所以沒有部件。
下面,我們就以Button爲例爲它自定義一個模板,注意,定義模板寫XAML比較花時間,你可以選擇使用設計工具Express Blend來完成,當然了,在學習的時候,最好還是動手寫一下。
  1. <phone:PhoneApplicationPage.Resources>  
  2.     <ControlTemplate x:Key="Template1" TargetType="ButtonBase">  
  3.         <Grid>  
  4.             <!--狀態組-->  
  5.             <VisualStateManager.VisualStateGroups>  
  6.                 <VisualStateGroup x:Name="CommonStates">  
  7.                     <VisualState x:Name="Normal"/>  
  8.                     <VisualState x:Name="MouseOver"/>  
  9.                     <VisualState x:Name="Pressed">  
  10.                         <Storyboard>  
  11.                             <DoubleAnimation  
  12.                                 Storyboard.TargetName="pressed"  
  13.                                 Storyboard.TargetProperty="Opacity"  
  14.                                 To="1" Duration="0:0:0.5"/>  
  15.                         </Storyboard>  
  16.                     </VisualState>  
  17.                     <VisualState x:Name="Disabled">  
  18.                         <Storyboard>  
  19.                             <DoubleAnimation  
  20.                                 Storyboard.TargetName="disable"  
  21.                                 Storyboard.TargetProperty="Opacity"  
  22.                                 To="0.5" Duration="0:0:0.5"/>  
  23.                         </Storyboard>  
  24.                     </VisualState>  
  25.                 </VisualStateGroup>  
  26.                 <VisualStateGroup x:Name="FocusStates">  
  27.                     <VisualState x:Name="Focused">  
  28.                         <Storyboard>  
  29.                             <DoubleAnimation  
  30.                                 Storyboard.TargetName="focussbd"  
  31.                                 Storyboard.TargetProperty="Opacity"  
  32.                                 To="0.88"/>  
  33.                         </Storyboard>  
  34.                     </VisualState>  
  35.                 </VisualStateGroup>  
  36.             </VisualStateManager.VisualStateGroups>  
  37.             <Border BorderBrush="{TemplateBinding BorderBrush}"  
  38.                     BorderThickness="{TemplateBinding BorderThickness}">  
  39.                 <Grid x:Name="background" Background="{TemplateBinding Background}">  
  40.                     <Rectangle x:Name="pressed" Opacity="0" RadiusX="2" RadiusY="2">  
  41.                         <Rectangle.Fill>  
  42.                             <LinearGradientBrush  
  43.                                 StartPoint=".5,0"  
  44.                                 EndPoint=".5,1">  
  45.                                 <GradientStop Color="SkyBlue" Offset=".1"/>  
  46.                                 <GradientStop Color="Blue" Offset=".9"/>  
  47.                             </LinearGradientBrush>  
  48.                         </Rectangle.Fill>  
  49.                     </Rectangle>  
  50.                     <ContentPresenter x:Name="ContentPresenter"  
  51.                                       HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"  
  52.                                       VerticalAlignment="{TemplateBinding VerticalContentAlignment}"  
  53.                                       Margin="{TemplateBinding Padding}"  
  54.                                       Content="{TemplateBinding Content}"  
  55.                                       ContentTemplate="{TemplateBinding ContentTemplate}"/>  
  56.                     <Rectangle x:Name="disable" Opacity="0" Fill="Gray" RadiusX="2" RadiusY="2"/>  
  57.                     <Border x:Name="focussbd" BorderBrush="LightGreen" BorderThickness="2" CornerRadius="2" Opacity="0"/>  
  58.   
  59.                 </Grid>  
  60.             </Border>  
  61.         </Grid>  
  62.     </ControlTemplate>  
  63. </phone:PhoneApplicationPage.Resources>  
  64.   
  65.     <Grid x:Name="ContentPanel"  Margin="12,0,12,0">  
  66.         <Button Content="Button" Height="72" HorizontalAlignment="Left" Margin="135,155,0,0" Name="button1" VerticalAlignment="Top" Width="160" Template="{StaticResource Template1}" />  
  67.     </Grid>  


控件模板有時候很難一兩句話講清楚,別看它好像很多東西,其實很簡單,它無非包括兩個東西——狀態和UI元素,至於怎麼個佈局法,完全取決於你希望怎麼設計了。

如果你說有什麼辦法可以幫助學習和研究控件模板,當然有的,前面說了,就是Express Blend這是一個很好用的設計工具,你把它當作圖形處理軟件也可以,它會根你的設計自動生成XAML,很好用。
Windows Phone SDK帶的這個工具是免費的,你在開發的過程中千萬不要小氣哦,大膽地去用吧,不用錢又這麼強大的東東,你不能浪費。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章