如何建立控制項的樣式 (WPF .NET)
使用 Windows Presentation Foundation (WPF),您可以使用自己的可重複使用樣式來自訂現有控制項的外觀。 樣式可以全域套用至您的應用程式、視窗和頁面,或直接套用至控制項。
建立樣式
您可以將 Style 想成是一種可將一組屬性值套用到一或多個元素的便利方式。 您可以在任何衍生自 FrameworkElement 或 FrameworkContentElement 的元素上使用樣式,例如 Window 或 Button。
宣告樣式的最常見方式是在 XAML 檔案的 Resources
區段中宣告成資源。 由於樣式是資源,因此會遵守適用於所有資源的範圍規則。 簡單地說,宣告樣式的位置會影響可套用該樣式的位置。 例如,如果您是在應用程式定義 XAML 檔案的根項目中宣告樣式,就可在應用程式中的任何地方使用該樣式。
<Application x:Class="IntroToStylingAndTemplating.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
StartupUri="WindowExplicitStyle.xaml">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="Header1" TargetType="TextBlock">
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
如果您在應用程式的其中一個 XAML 檔案中宣告樣式,則該樣式只能在該 XAML 檔案中使用。 如需有關資源範圍規則的詳細資訊,請參閱 XAML 資源概觀。
<Window x:Class="IntroToStylingAndTemplating.WindowSingleResource"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="WindowSingleResource" Height="450" Width="800">
<Window.Resources>
<Style x:Key="Header1" TargetType="TextBlock">
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</Window.Resources>
<Grid />
</Window>
樣式是由 <Setter>
子元素所組成,這些子元素會在套用樣式的元素上設定屬性。 在上述範例中,請注意,樣式會設定為透過 TargetType
屬性套用至 TextBlock
類型。 樣式會將 FontSize 設定為 15
,並將 FontWeight 設定為 ExtraBold
。 為樣式所變更的每個屬性新增 <Setter>
。
隱含套用樣式
Style 是將一組屬性值套用到多個元素的便利方式。 例如,請考慮下列 TextBlock 元素及其在視窗中的預設外觀。
<StackPanel>
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
您可以直接在每個 TextBlock 元素上設定 FontSize 和 FontFamily 等屬性,來變更預設外觀。 不過,如果您想要讓 TextBlock 元素共用某些屬性,您可以在 XAML 檔案的 Resources
區段中建立 Style,如下所示。
<Window.Resources>
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
當您將樣式的 TargetType 設定為 TextBlock 類型並省略 x:Key
屬性時,樣式會套用至限定為該樣式的所有 TextBlock 元素,這通常是 XAML 檔案本身。
現在,TextBlock 元素顯示如下。
明確套用樣式
如果您將具有值的 x:Key
屬性新增至樣式,則樣式不會再隱含地套用至 TargetType 的所有元素。 只有明確參考樣式的元素才會套用該樣式。
以下是上一節的樣式,但以 x:Key
屬性宣告。
<Window.Resources>
<Style x:Key="TitleText" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
若要套用樣式,請使用 StaticResource 標記延伸,將元素上的 Style 屬性設定為 x:Key
值,如下所示。
<StackPanel>
<TextBlock Style="{StaticResource TitleText}">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
請注意,第一個 TextBlock 元素已套用樣式,而第二個 TextBlock 元素則保持不變。 上一節的隱含樣式已變更為宣告 x:Key
屬性的樣式,這表示受該樣式影響的唯一元素就是直接參考該樣式的元素。
樣式一旦套用,不論明確或隱含,都會變成密封且無法變更。 如果您想要變更已套用的樣式,請建立新的樣式來取代現有的樣式。 如需詳細資訊,請參閱 IsSealed 屬性 (Property)。
您可以建立一個物件來根據自訂邏輯選擇要套用的樣式。 如需範例,請參閱為 StyleSelector 類別提供的範例。
以程式設計的方式套用樣式
若要以程式設計的方式將具名的樣式指派給元素,請從資源集合取得該樣式,然後將其指派給元素的 Style 屬性。 資源集合中項目的類型為 Object。 因此,您必須先將擷取的樣式轉換成 System.Windows.Style,再將其指派給 Style
屬性。 例如,下列程式碼會將名為 textblock1
的 TextBlock
樣式設定為已定義的樣式 TitleText
。
textblock1.Style = (Style)Resources["TitleText"];
textblock1.Style = CType(Resources("TitleText"), Windows.Style)
擴充樣式
也許您要讓兩個 TextBlock 元素共用一些屬性值,例如 FontFamily 和置中 HorizontalAlignment。 但同時也想要文字 [我的圖片] 有一些額外的屬性。 您可以建立一個以第一個樣式為基礎的新樣式來達到該目的,如下所示。
<Window.Resources>
<!-- .... other resources .... -->
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!--A Style that extends the previous TextBlock Style with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
然後,將樣式套 TextBlock
用至 。
<StackPanel>
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
此 TextBlock
樣式現在置中,使用 Comic Sans MS
字型,大小為 26
,前景色彩設定為範例中顯示的 LinearGradientBrush。 請注意,其會覆寫根據樣式的 FontSize 值。 如果 Style 中有多個 Setter 指向相同屬性,則最後宣告的 Setter
優先。
下列顯示 TextBlock 元素現在看起來的樣子:
此 TitleText
樣式會擴充已針對 TextBlock 類型所建立的樣式 (透過 BasedOn="{StaticResource {x:Type TextBlock}}"
參考)。 您也可以使用樣式的 x:Key
來擴充具有 x:Key
的樣式。 例如,如果有名為 Header1
的樣式,而您想要擴充該樣式,您可以使用 BasedOn="{StaticResource Header1}"
。
TargetType 屬性與 x:Key 屬性的關聯性
如先前所示,將 TargetType 屬性設定為 TextBlock
而不指派 x:Key
給樣式,會造成該樣式套用至所有 TextBlock 元素。 在此情況下,x:Key
會隱含地設定為 {x:Type TextBlock}
。 這表示如果您明確將 x:Key
值設定為 {x:Type TextBlock}
以外的任何值,則 Style 不會自動套用至所有 TextBlock
元素。 取而代之的是,您必須明確地將樣式 (藉由使用 x:Key
值) 套用到 TextBlock
元素。 如果您的樣式位於資源區段,而且您未在樣式上設定 TargetType
屬性,則必須設定 x:Key
屬性。
除了為 x:Key
提供預設值之外,TargetType
屬性還會指定要套用 setter 屬性的類型。 如果您未指定 TargetType
,則必須使用語法 Property="ClassName.Property"
,以類別名稱限定 Setter 物件中的屬性。 例如,您必須將 Property 設定為 "TextBlock.FontSize"
或 "Control.FontSize"
,而不是設定 Property="FontSize"
。
另請注意,許多 WPF 控制項都是由其他 WPF 控制項的組合所組成。 如果您建立一個套用到某個型別所有控制項的樣式,可能會獲得非預期的結果。 例如,如果您建立以 Window 中 TextBlock 類型為目標的樣式,即使 TextBlock
屬於另一個控制項 (例如 ListBox),該樣式也會套用至視窗中的所有 TextBlock
控制項。