如何建立控制項的樣式 (WPF .NET)

使用 Windows Presentation Foundation (WPF),您可以使用自己的可重複使用樣式來自訂現有控制項的外觀。 樣式可以全域套用至您的應用程式、視窗和頁面,或直接套用至控制項。

重要

.NET 7 和 .NET 6 的桌面指南檔正在建置中。

建立樣式

您可以將 視為 Style 將一組屬性值套用至一或多個元素的便利方式。 您可以在任何衍生自 FrameworkElement 或 例如 WindowFrameworkContentElementButton 的專案上使用樣式。

宣告樣式的最常見方式是作為 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 類型。 樣式會將 設定為 15 ,並將 FontWeight 設定 FontSizeExtraBold<Setter>針對每個屬性新增 樣式變更的 。

隱含套用樣式

Style是將一組屬性值套用至多個元素的便利方式。 例如,請考慮下列 TextBlock 元素及其在視窗中的預設面板。

<StackPanel>
    <TextBlock>My Pictures</TextBlock>
    <TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>

Styling sample screenshot before

您可以直接在每個元素上 TextBlock 設定 屬性,例如 FontSizeFontFamily ,來變更預設面板。 不過,如果您想要讓 TextBlock 元素共用某些屬性,您可以在 XAML 檔案的 區段中建立 StyleResources ,如下所示。

<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>

當您將樣式的 設定 TargetTypeTextBlock 類型並省略 x:Key 屬性時,樣式會套用至限定為樣式的所有 TextBlock 專案,這通常是 XAML 檔案本身。

現在元素 TextBlock 會顯示如下。

Styling sample screenshot base style

明確套用樣式

如果您將具有值的屬性新增 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 標記延伸 ,將 元素上的 屬性設定 Stylex:Key 值,如下所示。

<StackPanel>
    <TextBlock Style="{StaticResource TitleText}">My Pictures</TextBlock>
    <TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>

請注意,第一個專案已套用樣式,而第二個 TextBlock TextBlock 元素則保持不變。 上一節的隱含樣式已變更為宣告屬性的 x:Key 樣式,這表示受樣式影響的唯一元素就是直接參考樣式的專案。

Styling sample screenshot textblock

一旦套用樣式,明確或隱含地套用樣式,它就會變成密封且無法變更。 如果您想要變更已套用的樣式,請建立新的樣式來取代現有的樣式。 如需詳細資訊,請參閱 IsSealed 屬性 (Property)。

您可以建立一個物件來根據自訂邏輯選擇要套用的樣式。 如需範例,請參閱為 StyleSelector 類別提供的範例。

以程式設計方式套用樣式

若要以程式設計方式將具名樣式指派給專案,請從資源集合取得樣式,並將它指派給元素的 Style 屬性。 資源集合中的專案類型為 Object 。 因此,您必須先將擷取的樣式 System.Windows.Style 轉換成 ,再將它指派給 Style 屬性。 例如,下列程式碼會將名為 textblock1TextBlock 樣式設定為定義的樣式 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>
<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 基底樣式的值。 如果 中 StyleSetter 有多個 Setter 指向相同屬性,則最後宣告的 會優先使用 。

下列顯示 TextBlock 專案現在的外觀:

Styled TextBlocks

TitleText 樣式會擴充為 型別所建立的 TextBlock 樣式,以 BasedOn="{StaticResource {x:Type TextBlock}}" 參考。 您也可以使用 x:Key 樣式的 來擴充具有 x:Key 的樣式。 例如,如果有名為 Header1 的樣式,而您想要擴充該樣式,您可以使用 BasedOn="{StaticResource Header1}"

TargetType 屬性和 x:Key 屬性的關聯性

如先前所示,將 屬性設定 TargetTypeTextBlock 而不指派樣式,會導致將樣式 x:Key 套用至所有 TextBlock 專案。 在此情況下,x:Key 會隱含地設定為 {x:Type TextBlock}。 這表示如果您明確將值設定 x:Key 為 以外的 {x:Type TextBlock} 任何專案, Style 則 不會自動套用至所有 TextBlock 專案。 相反地,您必須將樣式(使用 x:Key 值)明確套用至 TextBlock 元素。 如果您的樣式位於 resources 區段,而且您未在樣式上設定 TargetType 屬性,則必須設定 x:Key 屬性。

除了提供 的預設值 x:Key 之外, TargetType 屬性也會指定 setter 屬性套用的型別。 如果您未指定 TargetType ,則必須使用 語法 Property="ClassName.Property" 來限定 物件中的 Setter 屬性與類別名稱。 例如,您必須將 設定為 或 ,而不是設定 Property="FontSize"Property"TextBlock.FontSize""Control.FontSize"

另請注意,許多 WPF 控制項是由其他 WPF 控制項的組合所組成。 如果您建立一個套用到某個型別所有控制項的樣式,可能會獲得非預期的結果。 例如,如果您建立以 中型別為目標的 TextBlock 樣式,則樣式會套用至視窗中的所有 TextBlock 控制項,即使 TextBlock 是另一個控制項的一部分,例如 ListBoxWindow

另請參閱