共用方式為


設定樣式和範本

Windows Presentation Foundation (WPF) 設計樣式和樣板化是一組功能套件 (樣式、樣板、觸發程序和腳本),可以讓開發人員和設計人員創造出色的視覺效果,並且為其產品建立一致的外觀。 雖然開發人員和 (或) 設計人員可以逐一針對個別應用程式的外觀進行大幅度的自訂設定,但是為了應用程式內部及跨應用程式外觀的維護與共用,仍然需要有一組功能強大的設計樣式及樣板化模型。 Windows Presentation Foundation (WPF) 即提供該模型。

WPF 樣式模型的另一項功能是將展示與邏輯分開來; 這表示,在開發人員使用 C# 或 Visual Basic 處理程式設計邏輯的同時,設計人員只使用 XAML 即可處理應用程式的外觀。

本概觀主要著重在應用程式的樣式設計和樣板化,因此並未討論任何資料繫結 (Data Binding) 的概念。 如需資料繫結的詳細資訊,請參閱資料繫結概觀

此外,您還必須了解資源的概念,因為資源可以讓您重複使用樣式和樣板。 如需資源的詳細資訊,請參閱資源概觀

這個主題包含下列章節。

  • 樣式設計和樣板化範例
  • 樣式基本概念
  • 資料範本
  • 控制項樣板
  • 觸發程序
  • 共用資源和佈景主題
  • 相關主題

樣式設計和樣板化範例

本概觀中使用的程式碼範例是以下圖中顯示的簡單相片範例為基礎:

已設定樣式的 ListView

這個簡單的相片範例使用樣式設計和樣板化來創造出色的使用者視覺體驗。 這個範例擁有兩個 TextBlock 項目和一個繫結至影像清單的 ListBox 控制項。 如需完整範例,請參閱設計樣式和樣板化簡介 (英文)。

樣式基本概念

您可以將 Style 視為一種方便使用者將一組屬性值套用到多個項目的方式。 例如,以下列 TextBlock 項目及其預設外觀為例:

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

設定樣式範例螢幕擷取畫面

您可以直接在每個 TextBlock 項目上設定如 FontSizeFontFamily 等屬性,以變更其預設外觀。 不過,如果您想讓 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 型別時,樣式便會套用到視窗中的所有 TextBlock 項目。

此時 TextBlock 項目顯示如下:

設定樣式範例螢幕擷取畫面

擴充樣式

您可能想讓兩個 TextBlock 項目共用某些屬性值,例如 FontFamily 和置中的 HorizontalAlignment,但同時又希望「我的圖片」這幾個字具有其他屬性。 如果要這樣做,您可以使用第一個樣式做為基礎來建立新樣式,如下所示:

<Window.Resources>


...


<!--A Style that extends the previous TextBlock Style-->
<!--This is a "named 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>

請注意,上述樣式會擁有 x:Key。 若要套用此樣式,請將 TextBlock 上的 Style 屬性設定為 x:Key 值,如下所示:

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

如範例中所示,這個 TextBlock 樣式現在的 HorizontalAlignment 值為 CenterFontFamily 值為 Comic Sans MS、FontSize 值為 26,而 Foreground 值則設為 LinearGradientBrush。 請注意,它會覆寫基底樣式的 FontSize 值。 如果 Style 中有一個以上的 Setter 設定相同的屬性,將優先採用最後宣告的 Setter

下圖顯示 TextBlock 項目現在的外觀:

已設定樣式的 TextBlock

這個 TitleText 樣式擴充了 TextBlock 型別已經建立的樣式。 您也可以使用 x:Key 值擴充具有 x:Key 的樣式。 如需範例,請參閱 BasedOn 屬性所提供的範例。

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="FontSize",而必須將 Property 設定為 "TextBlock.FontSize" 或 "Control.FontSize"。

另外請注意,許多 WPF 控制項都包含其他 WPF 控制項的組合。 如果您建立的樣式適用於某種型別的所有控制項,可能會產生無法預期的結果。 例如,如果您建立的樣式其目標為 Window 中的 TextBlock 型別,則該樣式會套用至視窗中的所有 TextBlock 控制項,即使 TextBlock 是另一個控制項 (例如 ListBox) 的一部分也一樣。

樣式和資源

您可以將樣式用在衍生自 FrameworkElementFrameworkContentElement 的任何項目上。 如前面的範例所示,宣告樣式最常用的方式是當做 XAML 檔案的 Resources 區段中的資源。 因為樣式是資源,所以它們會遵守所有資源都適用的相同範圍設定規則;宣告樣式的位置將會影響可以套用樣式的位置。 例如,如果您在應用程式定義 XAML 檔案的根項目中宣告樣式,該樣式即可在應用程式中的任一處使用。 如果您建立巡覽應用程式並在應用程式的其中一個 XAML 檔案中宣告樣式,則只能在該 XAML 檔案中使用此樣式。 如需資源之範圍設定規則的詳細資訊,請參閱資源概觀

此外,您還可以在本概觀後面的共用資源和佈景主題中找到樣式和資源的詳細資訊。

以程式設計方式設定樣式

若要以程式設計方式將具名樣式指派給項目,請從資源集合中取得樣式,並將它指派給項目的 Style 屬性。 請注意,資源集合中的項目屬於 Object 型別。 因此,您必須將衍生的樣式轉換為 Style,才能將它指派至 Style 屬性。 例如,若要在名為 textblock1 的 TextBlock 上設定已定義的 TitleText 樣式,請執行下列程式碼:

textblock1.Style = CType(Me.Resources("TitleText"), Style)
textblock1.Style = (Style)(this.Resources["TitleText"]);

請注意,一旦套用樣式之後,樣式就會密封而無法變更。 如果您想動態變更已經套用的樣式,必須建立新樣式來取代現有的樣式。 如需詳細資訊,請參閱 IsSealed 屬性 (Property)。

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

繫結、動態資源和事件處理常式

請注意,您可以使用 Setter.Value 屬性指定繫結標記延伸DynamicResource 標記延伸。 如需詳細資訊,請參閱 Setter.Value 屬性所提供的範例。

目前為止,本概觀只討論了如何使用 setter 來設定屬性值。 但是您也可以在樣式中指定事件處理常式。 如需詳細資訊,請參閱 EventSetter

資料範本

這個範例應用程式中有一個繫結到相片清單的 ListBox 控制項:

<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
         Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>

這個 ListBox 目前的外觀如下:

套用範本之前的 ListBox

大部分的控制項都有某種類型的內容,而這些內容通常是來自您所繫結的資料。 在這個範例中,這個資料就是相片清單。 在 WPF 中,您可使用 DataTemplate 定義資料的視覺呈現效果。 基本上,您放入 DataTemplate 的項目決定了這些資料在呈現之應用程式中的外觀。

在範例應用程式中,每個自訂 Photo 物件都有一個屬於字串型別的 Source 屬性,用於指定影像的檔案路徑。 這些相片物件目前都顯示為檔案路徑。

如果要讓相片顯示成影像,您必須建立 DataTemplate 做為資源:

<Window.Resources>


...


<!--DataTemplate to display Photos as images
    instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
  <Border Margin="3">
    <Image Source="{Binding Source}"/>
  </Border>
</DataTemplate>


...


</Window.Resources>

請注意,DataType 屬性與 StyleTargetType 屬性非常類似。 如果 DataTemplate 是在資源區段中,則當您將 DataType 屬性指定至某一型別,但是並未指派 x:Key 時,只要該型別出現就會套用 DataTemplate。 您永遠都可以選擇使用 x:Key 指派 DataTemplate,然後將它設定為 StaticResource,以用於採用 DataTemplate 型別的屬性,例如 ItemTemplate 屬性或 ContentTemplate 屬性。

基本上,上述範例中的 DataTemplate 定義了每當有 Photo 物件時,它都應該顯示成 Border 內的 Image。 套用此 DataTemplate 後,應用程式現在看起來就像這樣:

圖片影像

資料樣板化模型提供了其他功能。 例如,如果您要顯示的集合資料中包含使用 HeaderedItemsControl 型別 (例如 MenuTreeView) 的其他集合,可以使用 HierarchicalDataTemplate。 另一個資料樣板化功能是 DataTemplateSelector,它可以讓您根據自訂邏輯選擇所要使用的 DataTemplate。 如需詳細資訊,請參閱資料範本化概觀;其中提供了各種資料樣板化功能的深入討論。

控制項樣板

在 WPF 中,控制項的 ControlTemplate 定義了控制項的外觀。 您可以為控制項定義新的 ControlTemplate,以變更該控制項的結構和外觀。 在許多情況下,這種方式都能夠提供足夠的彈性,因此您不需要自行撰寫自訂控制項。 如需詳細資訊,請參閱 透過建立 ControlTemplate 自訂現有控制項的外觀

觸發程序

觸發程序可設定屬性,或是在變更屬性值或引發事件時啟動動作 (例如動畫)。 StyleControlTemplateDataTemplate 全部都有可以包含一組觸發程序 (Trigger) 的 Triggers 屬性。 觸發程序有許多種類型。

屬性觸發程序

設定屬性值或根據屬性值啟動動作的 Trigger 稱為屬性觸發程序。

為了示範如何使用屬性觸發程序,您可以將每個 ListBoxItem 設定成部分透明,但選取時除外。 下列樣式將 ListBoxItemOpacity 值設定為 0.5。 不過,當 IsSelected 屬性為 true 時,Opacity 便會設定為 1.0:

<Style TargetType="ListBoxItem">
  <Setter Property="Opacity" Value="0.5" />
  <Setter Property="MaxHeight" Value="75" />
  <Style.Triggers>
    <Trigger Property="IsSelected" Value="True">
        <Setter Property="Opacity" Value="1.0" />
    </Trigger>


...


  </Style.Triggers>
</Style>

這個範例使用 Trigger 設定屬性值,但請注意 Trigger 類別也有 EnterActionsExitActions 屬性,可以啟用觸發程序來執行動作。

請注意,ListBoxItemMaxHeight 屬性會設定為 75。 在下圖中,第三個項目為選取的項目:

已設定樣式的 ListView

EventTrigger 和 Storyboard

另一種觸發程序類型是 EventTrigger,它會根據發生的事件啟動一組動作。 例如,下列 EventTrigger 物件指定當滑鼠指標進入 ListBoxItem 時,MaxHeight 屬性會在 0.2 的期間內,產生值為 90 的動畫效果。 當滑鼠從項目移開時,此屬性便會在 1 秒的期間內恢復成原始值。 請注意,您不需要指定 MouseLeave 動畫的 To 值, 因為動畫可以追蹤原始值。

        <EventTrigger RoutedEvent="Mouse.MouseEnter">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <Storyboard>
                <DoubleAnimation
                  Duration="0:0:0.2"
                  Storyboard.TargetProperty="MaxHeight"
                  To="90"  />
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>
        <EventTrigger RoutedEvent="Mouse.MouseLeave">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <Storyboard>
                <DoubleAnimation
                  Duration="0:0:1"
                  Storyboard.TargetProperty="MaxHeight"  />
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>

如需詳細資訊,請參閱 腳本概觀

在下圖中,滑鼠會指向第三個項目:

設定樣式範例螢幕擷取畫面

MultiTrigger、DataTrigger 和 MultiDataTrigger

除了 TriggerEventTrigger 之外,還有其他類型的觸發程序。 MultiTrigger 可讓您根據多項條件設定屬性值。 當條件的屬性與資料繫結時,請使用 DataTriggerMultiDataTrigger

共用資源和佈景主題

一般的 Windows Presentation Foundation (WPF) 應用程式可能具有多項使用者介面 (UI) 資源可套用到整個應用程式。 整體來說,這組資源可以視為應用程式的佈景主題。 Windows Presentation Foundation (WPF) 提供使用封裝為 ResourceDictionary 類別之資源字典,將使用者介面 (UI) 資源封裝為佈景主題的支援。

Windows Presentation Foundation (WPF) 佈景主題是使用 Windows Presentation Foundation (WPF) 為了自訂任何項目之視覺效果而公開的設計樣式和樣板化機制來定義。

Windows Presentation Foundation (WPF) 佈景主題資源儲存在內嵌的資源字典中。 這些資源字典必須內嵌在簽署的組件內,而且可以內嵌在與程式碼本身相同的組件中,或是並存組件中。 以內含 Windows Presentation Foundation (WPF) 控制項的 PresentationFramework.dll 組件為例,佈景主題資源是位於一系列的並存組件中。

佈景主題會變成搜尋項目樣式時最後查看的位置。 搜尋作業通常是從項目樹狀結構向上查核以搜尋適當的資源開始,接著查看應用程式資源集合,最後再查詢系統。 這種方式使得應用程式開發人員在達到佈景主題之前,有機會在樹狀結構或應用程式層級重新定義任何項目的樣式。

您可以將資源字典定義成個別檔案,使您可以在多個應用程式之間重複使用佈景主題。 您也可以定義多個資源字典,使其提供相同的資源類型但具有不同的值,藉以建立可切換的佈景主題。 建議您透過設定應用程式的面板,在應用程式層級重新定義這些樣式或其他資源。

若要跨應用程式共用一組資源 (包括樣式和樣板),您可以建立 XAML 檔案並定義 ResourceDictionary。 例如,請看下圖顯示的部分使用 ControlTemplates 設定樣式範例 (英文):

控制項範本範例

若查看此範例中的 XAML 檔案,您會發現這些檔案都有下列內容:

<ResourceDictionary.MergedDictionaries>
  <ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>

這是 shared.xaml 的共用,其中定義的 ResourceDictionary 包含一組樣式和筆刷資源,可以讓範例中的控制項擁有一致的外觀。

如需詳細資訊,請參閱 合併的資源字典

如果您要建立自訂控制項的佈景主題,請參閱控制項撰寫概觀中的<外部控制項程式庫>一節。

請參閱

工作

HOW TO:尋找 ControlTemplate 產生的項目

HOW TO:尋找 DataTemplate 產生的項目

概念

WPF 中的 Pack URI