在前面資源一文中也提過樣式,樣式就如同我們做HTML頁排版時常用到的CSS樣式表,它是對於特定婁型的可視化元素,應該可以直接說是針對控制項的一種可重用的屬性設定列表,這樣對於需要設定相同屬性值的同類型的多個控制項來講是大大提高效率,我們不必要為每個控制項做重複的動作。
下面是一個TextBox的樣式樣本,我們希望通過引用資源中的樣式,使得頁面上的所有TextBox控制項都具有統一的外觀,而且都只能輸入數字。
<phone:PhoneApplicationPage.Resources><br /> <!--不帶key的樣式,應用於所有TextBlock元素--><br /> <Style TargetType="TextBlock"><br /> <Setter Property="FontSize" Value="40"/><br /> <Setter Property="Foreground" Value="Yellow"/><br /> </Style><br /> <!--帶key的樣式,只有引用該資源的元素才應用--><br /> <Style x:Key="MyTextBoxStyle" TargetType="TextBox"><br /> <Setter Property="FontSize" Value="40"/><br /> <Setter Property="Foreground" Value="Blue"/><br /> <Setter Property="InputScope"><br /> <Setter.Value><br /> <InputScope><br /> <InputScopeName NameValue="Number"/><br /> </InputScope><br /> </Setter.Value><br /> </Setter><br /> </Style><br /> </phone:PhoneApplicationPage.Resources><br /> <Grid x:Name="LayoutRoot" Background="Transparent"><br /> <Grid.RowDefinitions><br /> <RowDefinition Height="Auto"/><br /> <RowDefinition Height="*"/><br /> </Grid.RowDefinitions></p><p> <TextBlock Grid.Row="0" x:Name="PageTitle" Text="樣式樣本" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/></p><p> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,10,12,0"><br /> <Grid.RowDefinitions><br /> <RowDefinition Height="auto"/><br /> <RowDefinition Height="auto"/><br /> <RowDefinition Height="auto"/><br /> <RowDefinition Height="auto"/><br /> <RowDefinition Height="auto"/><br /> </Grid.RowDefinitions><br /> <Grid.ColumnDefinitions><br /> <ColumnDefinition Width="2*"/><br /> <ColumnDefinition Width="3*"/><br /> </Grid.ColumnDefinitions><br /> <TextBlock Grid.Column="0" Grid.Row="0" Text="文本一:"/><br /> <TextBlock Grid.Column="0" Grid.Row="1" Text="文本二:"/><br /> <TextBlock Grid.Column="0" Grid.Row="2" Text="文本三:"/><br /> <TextBlock Grid.Column="0" Grid.Row="3" Text="文本四:"/><br /> <TextBlock Grid.Column="0" Grid.Row="4" Text="文本五:"/></p><p> <TextBox Grid.Column="1" Grid.Row="0" Style="{StaticResource MyTextBoxStyle}" /><br /> <TextBox Grid.Column="1" Grid.Row="1" Style="{StaticResource MyTextBoxStyle}" /><br /> <TextBox Grid.Column="1" Grid.Row="2" Style="{StaticResource MyTextBoxStyle}" /><br /> <TextBox Grid.Column="1" Grid.Row="3"/><br /> <TextBox Grid.Column="1" Grid.Row="4"/><br /> </Grid><br /> </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控制項的狀態和部個有:
// 摘要:<br /> // 表示按鈕控制項。<br /> [TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]<br /> [TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]<br /> [TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]<br /> [TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")]<br /> [TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]<br /> [TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]<br /> public class Button : ButtonBase
Button控制項是內容控制項,它並不複雜,所以沒有組件。下面,我們就以Button為例為它自訂一個模板,注意,定義模板寫XAML比較花時間,你可以選擇使用設計工具Express Blend來完成,當然了,在學習的時候,最好還是動手寫一下。
<phone:PhoneApplicationPage.Resources><br /> <ControlTemplate x:Key="Template1" TargetType="ButtonBase"><br /> <Grid><br /> <!--狀態組--><br /> <VisualStateManager.VisualStateGroups><br /> <VisualStateGroup x:Name="CommonStates"><br /> <VisualState x:Name="Normal"/><br /> <VisualState x:Name="MouseOver"/><br /> <VisualState x:Name="Pressed"><br /> <Storyboard><br /> <DoubleAnimation<br /> Storyboard.TargetName="pressed"<br /> Storyboard.TargetProperty="Opacity"<br /> To="1" Duration="0:0:0.5"/><br /> </Storyboard><br /> </VisualState><br /> <VisualState x:Name="Disabled"><br /> <Storyboard><br /> <DoubleAnimation<br /> Storyboard.TargetName="disable"<br /> Storyboard.TargetProperty="Opacity"<br /> To="0.5" Duration="0:0:0.5"/><br /> </Storyboard><br /> </VisualState><br /> </VisualStateGroup><br /> <VisualStateGroup x:Name="FocusStates"><br /> <VisualState x:Name="Focused"><br /> <Storyboard><br /> <DoubleAnimation<br /> Storyboard.TargetName="focussbd"<br /> Storyboard.TargetProperty="Opacity"<br /> To="0.88"/><br /> </Storyboard><br /> </VisualState><br /> </VisualStateGroup><br /> </VisualStateManager.VisualStateGroups><br /> <Border BorderBrush="{TemplateBinding BorderBrush}"<br /> BorderThickness="{TemplateBinding BorderThickness}"><br /> <Grid x:Name="background" Background="{TemplateBinding Background}"><br /> <Rectangle x:Name="pressed" Opacity="0" RadiusX="2" RadiusY="2"><br /> <Rectangle.Fill><br /> <LinearGradientBrush<br /> StartPoint=".5,0"<br /> EndPoint=".5,1"><br /> <GradientStop Color="SkyBlue" Offset=".1"/><br /> <GradientStop Color="Blue" Offset=".9"/><br /> </LinearGradientBrush><br /> </Rectangle.Fill><br /> </Rectangle><br /> <ContentPresenter x:Name="ContentPresenter"<br /> HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"<br /> VerticalAlignment="{TemplateBinding VerticalContentAlignment}"<br /> Margin="{TemplateBinding Padding}"<br /> Content="{TemplateBinding Content}"<br /> ContentTemplate="{TemplateBinding ContentTemplate}"/><br /> <Rectangle x:Name="disable" Opacity="0" Fill="Gray" RadiusX="2" RadiusY="2"/><br /> <Border x:Name="focussbd" BorderBrush="LightGreen" BorderThickness="2" CornerRadius="2" Opacity="0"/></p><p> </Grid><br /> </Border><br /> </Grid><br /> </ControlTemplate><br /> </phone:PhoneApplicationPage.Resources></p><p> <Grid x:Name="ContentPanel" Margin="12,0,12,0"><br /> <Button Content="Button" Height="72" HorizontalAlignment="Left" Margin="135,155,0,0" Name="button1" VerticalAlignment="Top" Width="160" Template="{StaticResource Template1}" /><br /> </Grid>
控制項範本有時候很難一兩句話講清楚,別看它好像很多東西,其實很簡單,它無非包括兩個東西——狀態和UI元素,至於怎麼個布局法,完全取決於你希望怎麼設計了。
如果你說有什麼辦法可以協助學習和研究控制項範本,當然有的,前面說了,就是Express Blend這是一個很好用的設計工具,你把它當作圖形處理軟體也可以,它會根你的設計自動產生XAML,很好用。Windows Phone SDK帶的這個工具是免費的,你在開發的過程中千萬不要小氣哦,大膽地去用吧,不用錢又這麼強大的東東,你不能浪費。