WPF基礎之樣式設定和模板化

來源:互聯網
上載者:User

Windows Presentation Foundation (WPF) 樣式設定和模板化是指一套功能(樣式、模板、觸發器和示範圖板),應用程式、文檔或使用者介面 (UI) 的設計人員使用這些功能可以建立更好的視覺效果,也可以對其產品的統一外觀進行標準化。儘管作者或設計人員可以對應用程式的外觀逐個進行大量自訂動作,他們還是需要一個功能強大的樣式設定和模板化模型,以便在應用程式內部和應用程式之間維護和共用外觀。Windows Presentation Foundation (WPF) 就提供了這樣的模型。

WPF 樣式設定模型的另一個功能是實現表示形式與邏輯的分離。這意味著,在開發人員使用 C# 或 Visual Basic 進行邏輯編程時,設計人員只需使用 XAML 即可設計程式的外觀。

本概述將討論樣式設定和模板化樣本簡介應用程式,該應用程式具有兩個 TextBlock 元素,以及一個綁定到映像列表的 ListBox 控制項:

本概述主要討論該應用程式的樣式設定和模板化方面,而不討論任何資料繫結概念。

另外,瞭解資源也很重要,正是資源使得樣式和模板得以重用。

樣式基礎知識 您可以將 Style 看作是將一組屬性值應用到多個元素的捷徑。例如,考慮下面的 TextBlock 元素及其預設面板:

通過直接對每個 TextBlock 元素設定 FontSize 和 FontFamily 等屬性可以更改預設面板。但是,如果希望 TextBlock 元素可以共用某些屬性,則可以在 XAML 檔案的 Resources 節中建立一個 Style,如下所示:

將樣式的 TargetType 設定為 TextBlock 類型時,該樣式會應用於視窗中的所有 TextBlock 元素。

現在,TextBlock 元素的外觀如下:

擴充樣式 您可能希望兩個 TextBlock 元素共用某些屬性值(如 FontFamily 和置中的 HorizontalAlignment),同時還希望文本“我的圖片”具有某些其他屬性。在第一個樣式的基礎上建立一個新樣式可以達到這一目的,如下所示:

請注意,已為上面的樣式提供了 x:Key。若要應用該樣式,請將 TextBlock 的 Style 屬性設定為 x:Key 值,如下所示:

現在,此 TextBlock 樣式的 HorizontalAlignment 值為 Center,FontFamily 值為 Comic Sans MS,FontSize 值為 26,Foreground 值設定為樣本所示的 LinearGradientBrush。請注意,我們已重寫了基礎樣式的 FontSize 值。如果有多個 Setter 對 Style 的同一屬性進行設定,則最後聲明的 Setter 優先。

下面示範 TextBlock 元素現在的外觀:

此 TitleText 樣式擴充了為 TextBlock 類型建立的樣式。此外,使用 x:Key 值也可以擴充具有 x:Key 的樣式。

TargetType 屬性 (Property) 和 x:Key 屬性 (Attribute) 的關係 如第一個樣本所示,如果將 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 控制項,即使 TextBlock 是另一個控制項(如 ListBox)的組成部分也不例外。

樣式和資源 任何派生自 FrameworkElement 或 FrameworkContentElement 的元素都可以使用樣式。聲明樣式的最常見方式是將樣式作為 XAML 檔案的 Resources 節中的資源,如前面的樣本所示。由於樣式是資源,因此同樣遵循所有資源都適用的範圍規則:樣式的聲明位置決定樣式的應用範圍。例如,如果在應用程式定義 XAML 檔案的根項目中聲明樣式,則樣式可在應用程式範圍內使用。如果建立的是導航應用程式,並在該應用程式的某個 XAML 檔案中聲明樣式,則該樣式只能在該 XAML 檔案中使用。

以編程方式設定樣式 若要以編程方式向元素分配命名樣式,請從資源集合中擷取該樣式,然後將其分配給元素的 Style 屬性。請注意,資源集合中的項是 Object 類型,因此,將檢索到的樣式分配給 Style 屬性之前,必須將該樣式強制轉換為 Style。例如,若要對名為 textblock1 的 TextBlock 設定定義的 TitleText 樣式,請執行以下操作:

請注意,樣式一旦應用,便會密封並且無法更改。如果要動態更改已應用的樣式,必須建立一個新樣式來替換現有樣式。

您可以建立一個根據自訂邏輯選擇要應用的樣式的對象。

綁定、動態資源和事件處理常式 請注意,使用 Setter.Value 屬性可以指定 綁定標記延伸或 DynamicResource 標記延伸。

到目前為止,我們只討論了如何使用 setter 設定屬性值。在樣式中也可以指定事件處理常式。

資料範本 在本應用程式範例中,有一個綁定到照片列表的 ListBox 控制項。

此 ListBox 當前的外觀如下所示:

大多數控制項都具有某種類型的內容,這些內容通常來自綁定到的資料。在本樣本中,資料為照片列表。在 WPF 中,使用 DataTemplate 可以定義資料的可視表示形式。基本上,輸入 DataTemplate 的內容決定了資料在呈現的應用程式中的外觀。

在我們的應用程式範例中,每個自訂 Photo 對象都具有一個字串類型的 Source 屬性,該屬性指定映像的檔案路徑。當前,照片對象顯示為檔案路徑。

對於要顯示為映像的照片,可以將 DataTemplate 作為資源建立:

請注意,DataType 屬性與 Style 的 TargetType 屬性非常相似。如果 DataTemplate 位於資源部分,並且將 DataType 屬性指定為某個類型,也不為其分配 x:Key,則只要該類型出現,便會應用 DataTemplate。任何時候都可以為 DataTemplate 分配 x:Key,然後將其設定為 DataTemplate 類型的屬性(如 ItemTemplate 屬性或 ContentTemplate 屬性)的 StaticResource。

實質上,上面樣本的 DataTemplate 確定只要存在 Photo 對象,該對象就應作為 Image 顯示在 Border 中。通過此 DataTemplate,應用程式現在的外觀如下:

資料範本化模型還提供其他功能。例如,如果要使用 HeaderedItemsControl 類型(如 Menu 或 TreeView)顯示包含其他集合的集合資料,則可以使用 HierarchicalDataTemplate。另一個資料範本化功能是 DataTemplateSelector,利用這一功能可以根據自訂邏輯選擇要使用的 DataTemplate。有關更多資訊,請參見資料範本概述,該概述對不同的資料範本化功能進行了更加深入的討論。

控制項範本

請注意,我們的照片顯示為圖片,我們要水平顯示這些照片,而不是垂直顯示;我們希望 ListBox 是水平的。

不使用 ControlTemplate 首先,要使 ListBox 水平,不一定要使用 ControlTemplate,明確這一點很重要。ListBox 具有 ItemsPanel 屬性,利用該屬性可以設定 ItemsPanelTemplate,即控制 ListBox 的項的布局的模板。一種方法是只建立 ListBox 樣式,然後設定 ItemsPanel 屬性,如下例所示:

例表明,除了替換 ControlTemplate 之外,可能還有其他方法,這取決於具體的情況。在本樣本中,如果希望獲得具有其他屬性(如圓角)的水平 ListBox,則需要使用 ListBox 的 ControlTemplate。

在提供樣本來示範具體操作之前,首先需要說明 ControlTemplate 的概念。

什麼是 ControlTemplate? 大多數控制項都具有外觀和行為。以按鈕為例:外觀是可以按下的凸起地區,行為是在響應單擊時所引發的 Click 事件。

有時,控制項可以提供所需行為,但不具有所需外觀。到目前為止,我們已經示範了可以使用樣式 setter 來設定屬性值,從而影響控制項的外觀。但是,若要更改控制項的結構,或對組成控制項的組件設定屬性值,就需要使用 ControlTemplate。

在 WPF 中,控制項的 ControlTemplate 定義控制項的外觀。通過為控制項定義新的 ControlTemplate 可以更改控制項的結構和外觀。很多情況下,這種方法都足夠靈活,您不需要自己編寫自訂控制項。如果沒有為控制項定義自己的 ControlTemplate,則可以擷取與系統主題匹配的預設範本,該模板向 Button 控制項提供預設面板。

請注意:一旦為控制項建立 ControlTemplate,就會替換整個 ControlTemplate。例如,可以通過以下方式定義 Button ControlTemplate。

請注意,ContentPresenter 元素只標記 Button 的 Content 應出現在何處。後面有一節專門展開詳細討論。

應用此模板之後,Button 顯示為 Ellipse:

請記住,當 Button 具有焦點或按下時,其外觀都是將替換的按鈕的預設面板的組成部分。因此,您可能希望定義按鈕按下時的外觀,這取決於您的具體需要。

如果要建立 ControlTemplate,使用 ControlTemplate 樣本 是最好的入門方法。如果確實需要查看控制項的組成部分,可以查看位於主題的主題檔案,也可以使用 XAMLPad(隨 Windows 軟體開發套件 (SDK) 安裝的應用程式)的 Show Visual Tree 功能。

建立 ControlTemplate 現在,繼續示範樣本,我們建立一個 ControlTemplate,它定義一個水平的圓角 ListBox。若要替換控制項的 ControlTemplate,請將 Template 屬性設定為新的 ControlTemplate。

以這種方式設定 Template 屬性,實際上與使用 Style 設定其他控制項屬性沒有區別:您將 Style 用作一個工具來協助設定 Template 屬性。也就是說,設定 ControlTemplate 的另一種方法是直接設定控制項的 Template 屬性。如果以這種方式設定,則會在 Resources 節中建立一個 ControlTemplate,並為它提供 x:Key,然後將它作為靜態資源使用。

如上例所示,ControlTemplate 類具有 TargetType 屬性,該屬性類似於 Style 類的 TargetType 屬性。但要注意,與 Style 和 DataTemplate 不同,ControlTemplate 對象沒有隱式鍵的概念。換言之,如果有一個獨立 ControlTemplate,其 TargetType 屬性設定為某個類型,則 ControlTemplate 不會自動應用於該類型。另請注意,如果模板定義包含 ContentPresenter,則 ControlTemplate 需要 TargetType 屬性。

嘗試使用 ControlTemplate。例如,用 WrapPanel 替換 StackPanel,將 ScrollViewer 的 HorizontalScrollBarVisibility 屬性設定為 Disabled,然後將 ListBox 的寬度設定為 300。(只有第一行空間不足時,WrapPanel 才會將項放置到下一行。如果沒有將 ScrollViewer 的 HorizontalScrollBarVisibility 屬性設定為 Disabled,由於可以滾動到末尾,則第一行不會空間不足。因此,WrapPanel 不會對項進行換行。)

 

IsItemsHost 屬性 在此樣本中,一個必需的重要屬性是 IsItemsHost 屬性。IsItemsHost 屬性用於指示在 ItemsControl(如處理項列表的 ListBox 控制項)的模板中,產生的元素應放在什麼位置。如果將 StackPanel 的這一屬性設定為 true,則添加到 ListBox 的所有項都將進入 StackPanel。請注意,此屬性只對 Panel 類型有效。

ItemsPresenter 和 ContentPresenter 請注意,如果以這種方式在 ControlTemplate 中指定一個面板並將其標記為 IsItemsHost,控制項的使用者不使用 ControlTemplate 就無法替換 ItemsPanel。因此,除非您確信必須使用模板才能替換面板,否則不要採用這種方式。此外,您也可以使用 ItemsPresenter 元素來戳印金鑰的位置,然後通過設定 ItemsPanel 屬性來指定 ItemsPanelTemplate。ItemsPanelTemplate 頁提供了一個樣本,為您示範如何操作。

如果要建立 ContentControl(如 Button)的模板,則對應元素為 ContentPresenter。同樣,將此元素放置到 ContentControl 類型的 ControlTemplate 中,可以指示內容應在什麼位置顯示,如什麼是 ControlTemplate? 一節中的樣本所示。有關其他樣本,請參見 Label ControlTemplate 樣本和 ListBoxItem ControlTemplate 樣本。

TemplateBinding 在上一樣本中,需要注意的另一個重點是設定為 {TemplateBinding ListBox.Background} 的 Background 值。它只是指示 Border 的 Background 應與 ListBox 上設定的 Background 值同步。TemplatBinding 與 Binding 類似。實際上,TemplatBinding 比 Binding 更有效,但功能更弱;使用 TemplatBinding 等效於使用 Source 屬性設定為 RelativeSource.TemplatedParent 的 Binding。

若要使控制項使用者能夠控制某些屬性的值,可以在 ControlTemplate 中使用 TemplateBinding。TemplateBinding 是一個由 TemplateBindingExtension 類表示的標記延伸。

您可能已經注意到,DataTemplate 和 ControlTemplate 的相似之處在於它們的內容變成了對象的外觀。通過 ListBox ControlTemplate 定義,應用程式現在的外觀如下:

觸發器

Style、ControlTemplate 和 DataTemplate 都具有 Triggers 屬性,該熟悉可以包含一組觸發器。某個屬性值更改時,或某個事件引發時,觸發器會相應地設定屬性或啟動操作(如動畫操作)。

屬性觸發程序 為了示範如何使用觸發器來設定屬性,我們將每個 ListBoxItem 都設定為部分透明(除非它被選中)。

下面的樣式將 ListBoxItem 的 Opacity 值設定為 0.5。但是,當 IsSelected 屬性為 true 時,Opacity 設定為 1.0:

此樣本使用 Trigger 來設定屬性值,但請注意,Trigger 類還具有 EnterActions 和 ExitActions 屬性,通過這兩個屬性,觸發器可以執行操作。

請注意,我們還將 ListBoxItem 的 MaxHeight 屬性設定為 75。在下面的螢幕快照中,選中的項是第三項:

 

EventTrigger 和 Storyboard 我們剛剛示範了 Trigger 根據某個屬性的值來設定屬性值或啟動操作。另一種類型的觸發器是 EventTrigger,它根據事件的引發來啟動一組操作。例如,下面的 EventTrigger 對象指定當滑鼠指標進入 ListBoxItem 時,MaxHeight 屬性在 0.2 秒時間內以動畫方式增大為值 90。當滑鼠離開該項時,該屬性在 1 秒時間內還原為原始值。請注意為何無需為 MouseLeave 動畫指定 To 值。這是因為動畫能夠跟蹤原始值。

在下面的螢幕快照中,滑鼠指向第三項:

MultiTrigger、DataTrigger 和 MultiDataTrigger 除了 Trigger 和 EventTrigger 之外,還有其他類型的觸發器。通過 MultiTrigger,可以根據多個條件來設定屬性值。如果條件的屬性是經過資料繫結的,則可以使用 DataTrigger 和 MultiDataTrigger。

共用的資源和主題 典型 Windows Presentation Foundation (WPF) 應用程式可能具有多個在整個應用程式範圍內應用的使用者介面 (UI) 資源。概括地說,這組資源可視為應用程式的主題。通過使用封裝為 ResourceDictionary 類的資源字典,Windows Presentation Foundation (WPF) 支援將使用者介面 (UI) 資源打包為主題。

Windows Presentation Foundation (WPF) 主題是使用樣式設定和模板化機制定義的,Windows Presentation Foundation (WPF) 公開該機制,用於自訂任何元素的可視對象。

Windows Presentation Foundation (WPF) 佈景主題資源儲存在嵌入式資源字典中。這些資源字典必須嵌入到已簽名的程式集中,它們既可以嵌入到代碼自身所在的程式集中,也可以嵌入到並行程式集中。對於包含 Windows Presentation Foundation (WPF) 控制項的程式集 PresentationFramework.dll,佈景主題資源在一系列並行程式集中。

搜尋元素樣式時,主題是最後尋找的位置。通常,搜尋首先沿元素樹向上尋找相應資源,然後在應用程式資源集合中尋找,最後查詢系統。這為應用程式的作者提供了機會,讓他們可以在到達主題之前,在樹或應用程式級重新定義任何對象的樣式。

您可以將各資源字典分別定義為單個檔案,這樣就可以在多個應用程式中重用某個主題。通過定義多個提供相同類型資源、但具有不同值的資源字典,也可以建立可交換的主題。在設計應用程式外觀時,建議在應用程式級重新定義這些樣式或其他資源。

若要在多個應用程式中共用一組資源(包括樣式和模板),可以建立一個 XAML 檔案並定義一個 ResourceDictionary。例如,請看下面的螢幕快照,它顯示了使用 ControlTemplates 設定樣式的樣本的一部分:

如果查看樣本中的 XAML 檔案,您會注意到所有檔案都包含以下內容:

這是共用的 shared.xaml,該檔案定義一個 ResourceDictionary,該資源字典包含一組樣式和筆刷資源,使樣本中的控制項具有了一致的外觀。

摘自:http://developer.51cto.com/art/200808/86735.htm

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.