XAML 概觀 (WPF .NET)
本文說明 XAML 語言的功能,並示範如何使用 XAML 撰寫 Windows Presentation Foundation (WPF) 應用程式。 本文特別說明以 WPF 實作的 XAML。 就語言概念而言,XAML 本身涵蓋的範圍比 WPF 還要廣。
何謂 XAML
XAML 是一種宣告式的標記語言。 套用至 .NET 程式設計模型時,XAML 可簡化 .NET 應用程式的 UI 建立流程。 您可以在宣告式 XAML 標記中建立可見的 UI 項目,然後藉由使用程式碼後置 (Code-Behind) 的檔案 (已透過部分類別定義而聯結至該標記),區隔 UI 定義和執行階段邏輯。 XAML 會以組件中定義的一組支援型別,直接表示物件的執行個體化。 這一點有別於其他大部分的標記語言,通常大部分的標記語言是與支援型別系統沒有此種直接關連的直譯式語言。 XAML 會啟用工作流程,其中個別獨立的人員因而能夠使用不同的工具,操作應用程式的 UI 與邏輯。
XAML 檔案以文字表示時,則為通常有 .xaml
副檔名的 XML 檔案。 這些檔案可以採用任何 XML 編碼,但通常會採用 UTF-8 編碼。
下列範例示範如何在 UI 中建立按鈕。 這個範例可讓您一窺 XAML 如何呈現常用的 UI 程式設計共通法則,並不是完整的範例。
<StackPanel>
<Button Content="Click Me"/>
</StackPanel>
XAML 語法簡介
下列各節說明 XAML 語法的基本形式,並提供簡短的標記範例。 這些章節的目的並不在於提供每一種語法格式的相關完整資訊,例如在支援類型系統中的呈現方式。 如需 XAML 語法細節的詳細資訊,請參閱 XAML 語法詳細資料。
若您之前已經熟悉 XML 語言,則下面幾節中的大部分內容對您而言都很簡單。 這是因為 XAML 的其中一個基本設計原則所致。 XAML 語言會定義自己的概念,但是這些概念是在 XML 語言和標記形式內運作。
XAML 物件元素
物件元素通常會宣告型別的執行個體。 該類型是在使用 XAML 語言之技術所參考的組件中定義。
物件元素語法一定是以左角括弧 (<
) 開始。 之後接著您要用於建立執行個體之型別的名稱 (名稱可以包含前置詞,稍後會說明此概念)。之後,您就可以選擇是否在物件元素上宣告屬性。 然後,以右角括弧 (>
) 結束,即可完成物件元素標記。 您也可以透過正斜線加上右角括弧 (/>
) 的組合完成標記,改為使用不含任何內容的自我結尾格式。 例如,請回顧先前示範的標記程式碼片段。
<StackPanel>
<Button Content="Click Me"/>
</StackPanel>
此範例指定兩個物件元素:<StackPanel>
(含內容且其後接著結束標記) 以及 <Button .../>
(自我結尾格式,具有數個屬性)。 物件元素 StackPanel
和 Button
會個別對應到的類別名稱,是由 WPF 所定義的,並會作為 WPF 組件的一部分。 當您指定物件元素標記時,您會建立 XAML 處理指示以建立新的基礎類型執行個體。 在剖析和載入 XAML 時,即會呼叫基礎類型的無參數建構函式來建立每個執行個體。
屬性 (Attribute) 語法 (屬性(Property))
物件的屬性 (Property) 通常能夠以物件元素的屬性 (Attribute) 來表示。 屬性 (Attribute) 語法會命名要設定的物件屬性 (Property),並且緊接著指派運算子 (=)。 屬性 (Attribute) 的值一定是以利用引號括住的字串指定。
對於過去曾經使用標記語言的開發人員而言,屬性 (Attribute) 語法是最有效率的屬性 (Property) 設定語法,也是最為直覺化的使用語法。 例如,下列標記建立的按鈕會以藍底紅字顯示 Content
文字。
<Button Background="Blue" Foreground="Red" Content="This is a button"/>
屬性元素語法
對於物件元素的某些屬性 (Property) 而言,屬性 (Attribute) 語法並不適用,這是因為在屬性 (Attribute) 語法的引號與字串限制下,無法適當表達提供屬性 (Property) 值所需的物件和資訊。 對於這種情況,可以使用另一種稱為屬性 (Property) 元素語法的語法。
屬性 (Property) 元素開始標記的語法是 <TypeName.PropertyName>
。 該標記的內容通常會是類型的物件元素 (屬性 (Property) 會以該類型作為其值)。 指定內容後,您必須以結束標記結束屬性 (Property) 元素。 結束標記的語法為 </TypeName.PropertyName>
。
若可以使用屬性 (Attribute) 語法,則使用屬性 (Attribute) 語法通常比較方便,並且可以讓標記 (Markup) 更為精簡,不過這通常只是樣式上的問題,而非技術上的限制。 下列範例顯示的屬性 (Property) 會設定成跟上述屬性 (Attribute) 語法範例相同,但這次會對 Button
的所有屬性 (Property) 使用屬性 (Property) 元素語法。
<Button>
<Button.Background>
<SolidColorBrush Color="Blue"/>
</Button.Background>
<Button.Foreground>
<SolidColorBrush Color="Red"/>
</Button.Foreground>
<Button.Content>
This is a button
</Button.Content>
</Button>
集合語法
XAML 語言包含一些最佳化特色,能夠產生可讀性更高的標記。 其中一項最佳化特點就是,如果特定屬性 (Property) 採用集合型別,那麼您於標記中宣告為該屬性值之子元素的項目,就會變成該集合的一部分。 在此情況下,子物件元素的集合會成為要設定給該集合屬性的值。
以下範例示範設定 GradientStops 屬性值的集合語法。
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<!-- no explicit new GradientStopCollection, parser knows how to find or create -->
<GradientStop Offset="0.0" Color="Red" />
<GradientStop Offset="1.0" Color="Blue" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
XAML 內容屬性
XAML 指定了一個語言功能,類別可藉此確實指派其中一個屬性作為 XAML「內容」屬性。 該物件元素的子元素會用來設定該內容屬性的值。 換言之,對於內容屬性而言 (其他類屬性則不適用),以 XAML 標記設定該屬性時,您可以省略屬性元素,進而在標記中產生更加明顯可見的父/子比喻。
例如,Border 指定 的「內容」Child屬性。 下面兩個 Border 元素可視為完全相同。 第一個利用內容屬性語法的優點,省略了 Border.Child
屬性元素。 第二個則明確顯示 Border.Child
。
<Border>
<TextBox Width="300"/>
</Border>
<!--explicit equivalent-->
<Border>
<Border.Child>
<TextBox Width="300"/>
</Border.Child>
</Border>
根據 XAML 語言的規則,XAML 內容屬性值必須完全放在該物件元素上任何其他屬性元素之前或之後。 例如,下列標記無法編譯。
<Button>I am a
<Button.Background>Blue</Button.Background>
blue button</Button>
如需 XAML 語法細節的詳細資訊,請參閱 XAML 語法詳細資料。
文字內容
少數 XAML 元素可以直接將文字作為其內容加以處理。 若要啟用這項功能,必須符合下列其中一種情況:
類別必須宣告內容屬性,且該內容屬性的類型必須是可以指派給字串的類型 (類型可能是 Object)。 例如,任何 ContentControl 都會使用 Content 作為其內容屬性和類型 Object,而這支援 ContentControl 的下列用法,例如 Button :
<Button>Hello</Button>
。該型別必須宣告型別轉換子,此時,文字內容便會作為該型別轉換子的初始設定文字。 例如,
<Brush>Blue</Brush>
會將Blue
的內容值轉換成筆刷。 這種案例在實務中較不常見。型別必須是已知的 XAML 語言基本型別。
內容屬性和集合語法合併
請思考此範例。
<StackPanel>
<Button>First Button</Button>
<Button>Second Button</Button>
</StackPanel>
這裡的每一個 Button 都是 StackPanel 的子元素。 這段有效率而直覺化的標記 (Markup),是基於兩個不同理由省略兩個標記 (Tag)。
省略了 StackPanel.Children 屬性元素:StackPanel 衍生自 Panel。 Panel 會將 Panel.Children 定義為其 XAML 內容屬性。
省略了 UIElementCollection 物件元素:Panel.Children 屬性採用 UIElementCollection 類型,其可實作 IList。 根據 XAML 處理集合 (例如 IList) 的規則,集合的元素標記可以省略。 (在本例中,UIElementCollection 其實不會具現化,因為其並不會公開無參數的建構函式,這也是 UIElementCollection 物件元素以註解顯示的原因)。
<StackPanel>
<StackPanel.Children>
<!--<UIElementCollection>-->
<Button>First Button</Button>
<Button>Second Button</Button>
<!--</UIElementCollection>-->
</StackPanel.Children>
</StackPanel>
屬性 (Attribute) 語法 (事件)
屬性 (Attribute) 語法也可以供屬於事件而非屬性 (Property) 的成員使用。 在此情況下,屬性 (Attribute) 名稱就是事件名稱。 在 WPF 的 XAML 事件實作中,屬性 (Attribute) 值會是實作該事件委派之事件處理常式的名稱。 例如,下列標記會將 Click 事件的處理常式指派給使用標記建立的 Button:
<Button Click="Button_Click" >Click Me!</Button>
除了這個屬性 (Attribute) 語法的範例,WPF 中還有更多事件與 XAML 的應用內容。 例如,您也許好奇在此所參照的 ClickHandler
究竟代表什麼以及它是如何定義的。 本文接下來的事件和 XAML 程式碼後置一節中便會詳加說明。
XAML 中的大小寫和空白字元
一般而言,XAML 要區分大小寫。 為了能夠解析支援類型,WPF XAML 會和 CLR 同樣遵守區分大小寫的規則。 在依名稱與組件的基礎型別或與型別的成員進行比較時,物件元素、屬性 (Property) 元素和屬性 (Attribute) 名稱都必須以區分大小寫的方式指定。 XAML 語言關鍵字和基本類型也區分大小寫。 值則不一定區分大小寫。 值是否會區分大小寫的決定因素,在於採用該值的屬性 (Property) 或屬性 (Property) 值型別的相關型別轉換子行為。 例如,採用 Boolean 類型的屬性 (Property) 會將 true
或 True
視為對等值,但這只是因為原生 WPF XAML 剖析器類型轉換已支援將字串轉換成 Boolean,因此可以使用這些對等用法。
WPF XAML 處理器和序列化程式會忽略或捨棄所有不重要的空白字元,並將任何必要的空白字元標準化。 這與指定 XAML 時所預設的空白字元行為建議一致。 這個行為只不過是您在 XAML 內容屬性 (Property) 內指定字串的必然結果。 簡單地說,XAML 會將空格、換行字元和定位字元轉換成為空格,然後在連續字串兩端發現空格時保留一個空格。 本文不討論 XAML 空白字元處理的完整說明。 如需詳細資訊,請參閱 XAML 中的空白字元處理。
標記延伸
標記延伸是一種 XAML 語言的概念。 大括號 ({
和 }
) 用於提供屬性 (Attribute) 語法的值時,表示的是一種標記延伸用法。 這項使用會指引 XAML 處理跳脫一般的屬性 (Attribute) 值處理方式 (即視為常值字串或字串可轉換值)。
WPF 應用程式設計中最常使用的標記延伸是用於資料繫結運算式的 Binding
,以及資源參考 StaticResource
和 DynamicResource
。 使用標記延伸就可以使用屬性 (Attribute) 語法為屬性 (Property) 提供值,即使該屬性 (Property) 通常不支援屬性 (Attribute) 語法也一樣。 標記延伸經常使用中繼運算式類型啟用延後值或參考其他物件這類僅出現在執行階段的功能。
例如,下列標記使用屬性 (Attribute) 語法來設定 Style 屬性 (Property) 值。
Style 屬性 (Property) 會採用 Style 類別的執行個體,根據預設,該類別不可以由屬性 (Attribute) 語法字串來具現化。 但在此情況下,屬性 (Attribute) 會參考特定的標記延伸 StaticResource
。 當處理該標記延伸時,所傳回的樣式參考先前是以資源字典中的調整資源來執行個體化。
<Window x:Class="index.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="100" Width="300">
<Window.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="BorderBrush" Value="Blue"/>
<Setter Property="BorderThickness" Value="5" />
</Style>
</Window.Resources>
<Border Style="{StaticResource PageBackground}">
<StackPanel>
<TextBlock Text="Hello" />
</StackPanel>
</Border>
</Window>
如需 WPF 中特別實作之所有 XAML 標記延伸的參考清單,請參閱 WPF XAML 擴充功能。 如需由 System.Xaml 所定義且更廣泛存在於 .NET XAML 實作的標記延伸參考清單,請參閱 XAML 命名空間 (x:) 語言功能。 如需標記延伸概念的詳細資訊,請參閱標記延伸和 WPF XAML。
類型轉換器
XAML 語法簡介一節中說明了屬性 (Attribute) 值必須要能夠由字串進行設定。 字串轉換成其他物件類型或基本值的基本原始處理方式,除了依據特定類型的原生處理 (例如 String 或 DateTime 之外),還會依據 Uri 類型本身。 但是,這些類型的許多 WPF 類型或成員會擴充基本字串屬性處理行為,使得更多複雜物件類型的執行個體能夠指定為字串與屬性。
Thickness 結構就是啟用 XAML 用法類型轉換的類型範例。 Thickness 會指出巢狀矩形內的度量,並且作為屬性 (Property) (例如 Margin) 的值使用。 透過在 Thickness 上放置類型轉換子的方式,使用 Thickness 的所有屬性 (Property) 都可以更輕易地以 XAML 指定,因為這些屬性 (Property) 可以指定為屬性 (Attribute)。 以下範例使用類型轉換與屬性 (Attribute) 語法,提供 Margin 的值:
<Button Margin="10,20,10,30" Content="Click me"/>
上述屬性 (Attribute) 語法範例與下列更為詳細的語法範例相當,但 Margin 改以透過包含 Thickness 物件元素的屬性 (Property) 元素語法所設定。 Thickness 的四個主要屬性 (Property) 都會在新的執行個體上設為屬性 (Attribute):
<Button Content="Click me">
<Button.Margin>
<Thickness Left="10" Top="20" Right="10" Bottom="30"/>
</Button.Margin>
</Button>
注意
對於少部分的物件而言,因為類型本身並沒有無參數建構函式,所以類型轉換是唯一可以將屬性 (Property) 設定為該類型而不需動用子類別的公用方式。 例如 Cursor。
如需類型轉型的詳細資訊,請參閱TypeConverters 和 XAML。
根元素和命名空間
XAML 檔案只能有一個根元素,這樣才能同時成為格式正確的 XML 檔案和有效的 XAML 檔案。 在一般的 WPF 案例中,您會使用在 WPF 應用程式模型中具有特殊意義的根元素 (例如,頁面的 Window 或 Page、外部字典的 ResourceDictionary,或者應用程式定義的 Application)。 以下範例顯示 WPF 頁面之一般 XAML 檔案的根元素,根元素為 Page。
<Page x:Class="index.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1">
</Page>
根元素也包含屬性 (Attribute) xmlns
和 xmlns:x
。 這些屬性會向 XAML 處理器指出哪些 XAML 命名空間包含支援型別 (標記會將這些型別參考為元素) 的型別定義。
xmlns
屬性會特別指出預設的 XAML 命名空間。 在預設的 XAML 命名空間內,標記中的物件元素可以不使用前置詞指定。 對於大部分的 WPF 應用程式案例,以及 SDK WPF 章節中提供的幾乎所有範例而言,預設 XAML 命名空間都會對應至 WPF 命名空間 http://schemas.microsoft.com/winfx/2006/xaml/presentation
。
xmlns:x
屬性會指定另一個對應 XAML 語言命名空間 http://schemas.microsoft.com/winfx/2006/xaml
的命名空間。
使用 xmlns
定義命名空間使用和對應的範圍,與 XML 1.0 規格是一致的。 XAML 命名空間與 XML 命名空間唯一的差異在於,XAML 命名空間也帶有其他意涵,指出當涉及型別解析和剖析 XAML 時,型別會如何支援名稱範圍的元素。
只有每個 XAML 檔案的根元素才必須要有 xmlns
屬性。
xmlns
定義會套用至根元素的所有子元素上 (這個行為再度與 xmlns
的 XML 1.0 規格一致)。xmlns
屬性也可以用在根元素底下的其他元素上,而且應該套用至定義元素下的任何子元素。 然而,過於頻繁地定義或重新定義 XAML 命名空間會造成 XAML 標記樣式難以閱讀。
其 XAML 處理器的 WPF 實作包含能夠辨認 WPF 核心組件的基礎結構。 廣為人知的一點是,WPF 核心組件包含支援將 WPF 對應至預設 XAML 命名空間的類型。 這項功能可以透過屬於專案組建檔以及 WPF 組建與專案系統的組態進行啟用。 因此,必須將預設的 XAML 命名空間宣告為預設的 xmlns
,才能夠參考來自 WPF 組件的 XAML 元素。
x: 前置詞
在先前的根元素範例中,前置詞 x:
會用於對應 XAML 命名空間 http://schemas.microsoft.com/winfx/2006/xaml
,它是支援 XAML 語言建構的專屬 XAML 命名空間。 這個 x:
前置詞會用於對應範例中專案範本的這個 XAML 命名空間,同時整份 SDK 文件中也會使用這個前置詞。 XAML 語言的 XAML 命名空間包含數種您在 XAML 中經常使用的程式設計建構。 下列清單是您最常使用的 x:
前置詞程式設計建構:
x:Key:為 ResourceDictionary (或其他架構中類似字典的概念) 中的每個資源,設定唯一索引鍵。 通常在 WPF 應用程式標記中看到的
x:Key
,大概有 90% 都是x:
。x:Class:為提供 XAML 頁面程式碼後置的類別,指定類別的 CLR 命名空間與類別名稱。 依據 WPF 程式撰寫模型,您必須有這類支援程式碼後置的類別,因此您幾乎都會看到
x:
對應,即使沒有資源也一樣。x:Name:針對處理物件元素後存在於執行階段程式碼中的執行個體,指定執行階段物件名稱。 一般而言,您經常會使用 WPF 針對 x:Name 所定義的對等屬性。 這類屬性專門對應至 CLR 支援屬性,因此對於您經常使用執行階段程式碼來尋找已初始化 XAML 中之具名元素的應用程式設計情境而言,會更方便。 這類屬性最常見的就是 FrameworkElement.Name。 如果特定類別中不支援對等 WPF 架構層級 屬性,您仍可使用 Name。 這會發生在某些動畫案例中。
x:Static:啟用會傳回靜態值的參考,這個值在其他狀況下無法相容於 XAML 的屬性。
x:Type:依據類型名稱建構 Type 參考。 這是用於指定會採用 Type 的屬性 (Attribute),例如 Style.TargetType,但是因為屬性 (Property) 經常具有原生的字串對 Type 轉換,因此不使用 x:Type 標記延伸也沒關係。
x:
前置詞/XAML 命名空間中還有其他的程式設計建構,但並不常用。 如需詳細資訊,請參閱 XAML 命名空間 (x:) 語言功能。
自訂前置詞與自訂類型
對於您自己的自訂組件或是 WPF 核心 (PresentationCore、PresentationFramework 和 WindowsBase) 以外的組件,您可以在自訂的 xmlns
對應中指定此組件。 接著,只要型別已正確實作為可以支援您嘗試進行的 XAML 用法,您便可以在您的 XAML 中參考該組件中的型別。
下例為自訂前置詞在 XAML 標記中運作的基本範例。 前置詞 custom
會定義於根元素標記中,且對應到已封裝並隨應用程式提供的特定組件。 這個組件包含 NumericUpDown
型別,會實作該型別以支援一般的 XAML 用法,以及使用類別繼承,這個類別繼承允許在 WPF XAML 內容模型的特定點置中插入這個型別。 這個 NumericUpDown
控制項的執行個體會使用前置詞宣告為物件元素,如此一來,XAML 剖析器便能得知哪一個 XAML 命名空間包含型別,因此支援組件的所在便是包含型別定義的位置。
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:NumericUpDownCustomControl;assembly=CustomLibrary"
>
<StackPanel Name="LayoutRoot">
<custom:NumericUpDown Name="numericCtrl1" Width="100" Height="60"/>
...
</StackPanel>
</Page>
如需 XAML 中自訂型別的詳細資訊,請參閱 WPF 的 XAML 和自訂類別。
如需組件中 XML 命名空間和程式碼命名空間關聯方式的詳細資訊,請參閱 WPF XAML 的 XAML 命名空間和命名空間對應。
事件和 XAML 程式碼後置
大部分的 WPF 應用程式是由 XAML 標記和程式碼後置所組成。 在專案中,XAML 會撰寫為 .xaml
檔案,而 Microsoft Visual Basic 或 C# 這類的 CLR 語言則用於撰寫程式碼後置檔案。 將 XAML 檔案作為 WPF 程式設計和應用程式模型的一部分而進行標記編譯時,XAML 檔案的 XAML 程式碼後置檔案的位置,是藉由指定命名空間和類別作為 XAML 根元素的 x:Class
屬性 (Attribute) 來識別。
在目前的範例中,您已經看過幾種按鈕,但沒有一個按鈕具有任何相關聯的邏輯行為。 用於新增物件元素行為的主要應用程式層級機制,是使用元素類別的現有事件,並為該事件撰寫在執行階段引發該事件時所叫用的特定處理常式。 要使用的事件名稱和處理常式名稱是在標記中指定的,而實作處理常式的程式碼則是在程式碼後置中定義。
<Page x:Class="ExampleNamespace.ExamplePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Button Click="Button_Click">Click me</Button>
</StackPanel>
</Page>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace ExampleNamespace;
public partial class ExamplePage : Page
{
public ExamplePage() =>
InitializeComponent();
private void Button_Click(object sender, RoutedEventArgs e)
{
var buttonControl = (Button)e.Source;
buttonControl.Foreground = Brushes.Red;
}
}
Class ExamplePage
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
Dim buttonControl = DirectCast(e.Source, Button)
buttonControl.Foreground = Brushes.Red
End Sub
End Class
請注意,程式碼後置檔案會使用 CLR 命名空間 ExampleNamespace
(Visual Basic 中看不到此命名空間),並宣告 ExamplePage
作為該命名空間內的部分類別。 這會平行處理 x:Class
的 ExampleNamespace
屬性值。標記根目錄中提供的 ExamplePage
。 WPF 標記編譯器會藉由從根元素型別衍生類別,為任何編譯的 XAML 檔案建立部分類別。 當您提供的程式碼後置也會定義相同的部分類別時,所產生的程式碼會合併到已編譯應用程式的相同命名空間和類別內。
重要
在 Visual Basic 中,XAML 和程式碼後置檔案都會隱含根命名空間。 只有巢狀命名空間是可見的。 本文會示範 C# 專案的 XAML。
如需 WPF 中程式碼後置程式設計之需求的詳細資訊,請參閱 WPF 中的程式碼後置、事件處理常式和部分類別需求。
如果不想要建立獨立的程式碼後置檔案,您也可以在 XAML 檔案中內嵌程式碼。 然而,內嵌程式碼具有基本的限制,是一個用途較少的技術。 如需詳細資訊,請參閱 WPF 中的程式碼後置和 XAML。
路由事件
對 WPF 來說有一個基本的特別事件功能,即為路由事件。 路由事件可以讓元素處理由其他元素引發的事件,只要元素可以透過樹狀結構關係來連接即可。 在使用 XAML 屬性 (Attribute) 指定事件處理時,路由事件可以由任何元素接聽和處理,包括類別成員表中沒有列出該特定事件的元素。 這可以藉由使用主控類別名稱來限定事件名稱屬性而達成。 例如,在持續進行的 StackPanel
StackPanel
/ 範例中的父元素 Button
,可以註冊子元素按鈕的 Click 事件的處理常式,方法是在 Button.Click
物件元素上指定屬性 StackPanel
,並將處理常式名稱設為屬性值。 如需詳細資訊,請參閱路由事件概觀。
具名元素
根據預設,藉由處理 XAML 物件元素而建立於物件圖形中的物件執行個體,沒有唯一識別碼或物件參考。 相反地,如果在程式碼中呼叫建構函式,您幾乎都是使用建構函式結果來設定所建構執行個體的變數,這樣您可於稍後在程式碼中參考執行個體。 為了要對透過標記定義建立的物件提供標準化存取,XAML 定義了 x:Name 屬性。 您可以對任何物件元素設定 x:Name
屬性值。 在程式碼後置中,您選擇的識別項等同於代表所建構執行個體的執行個體變數。 就各方面來說,具名元素的運作方式就如同它們是物件執行個體一樣 (名稱會參考該執行個體),而您的程式碼後置可以參考具名元素來處理應用程式內的執行階段互動。 執行個體與變數之間的這種關聯是由 WPF XAML 標記編譯器來達成,更明確地說,其會使用 InitializeComponent 之類的功能與模式,但本文不會再就這些功能與模式進行詳細討論。
WPF 架構層級的 XAML 元素會繼承 Name 屬性 (Property),該屬性 (Property) 等同於 XAML 定義的 x:Name
屬性 (Attribute)。 某些其他類別也會提供 x:Name
的屬性 (Property) 層級對等用法,通常也會定義為 Name
屬性 (Property)。 一般來說,如果在成員表中找不到您所選元素/類型的 Name
屬性 (Property),請改用 x:Name
。
x:Name
值會提供 XAML 元素的識別碼,這個識別碼可在執行階段供特定子系統或公用程式方法 (例如 FindName) 使用。
以下範例會在 Name 元素中設定 StackPanel。 然後,在 Button 內,StackPanel 的處理常式會透過其執行個體參考 StackPanel 來參考 buttonContainer
,如 Name 所設定。
<StackPanel Name="buttonContainer">
<Button Click="RemoveThis_Click">Click to remove this button</Button>
</StackPanel>
private void RemoveThis_Click(object sender, RoutedEventArgs e)
{
var element = (FrameworkElement)e.Source;
if (buttonContainer.Children.Contains(element))
buttonContainer.Children.Remove(element);
}
Private Sub RemoveThis_Click(sender As Object, e As RoutedEventArgs)
Dim element = DirectCast(e.Source, FrameworkElement)
If buttonContainer.Children.Contains(element) Then
buttonContainer.Children.Remove(element)
End If
End Sub
就如同變數一樣,執行個體的 XAML 名稱是由範圍的概念所控制,所以可以強制名稱在可預測的部分範圍內是唯一的。 定義頁面的主要標記,表示一個唯一的 XAML 名稱範圍,而 XAML 名稱範圍的界限則是該頁面的根元素。 然而,其他的標記來源可以於執行階段與頁面互動,例如樣式或樣式內的範本,而這類標記來源通常具有自己的 XAML 名稱範圍,其名稱範圍並不一定與頁面的 XAML 名稱範圍有所連接。 如需 x:Name
和 XAML 名稱範圍的詳細資訊,請參閱 Name、x:Name 指示詞 或 WPF XAML 名稱範圍。
附加屬性和附加事件
XAML 指定了一個語言功能,可在任何元素上指定某些屬性 (Property) 或事件,即使設定所在元素的類型定義中沒有該屬性或事件。 這個功能的屬性版本稱為附加屬性,事件版本則稱為附加事件。 在概念上來說,您可以將附加屬性和附加事件,想像成是可以在任何 XAML 元素/物件執行個體上設定的全域成員。 不過,該元素/類別或整個基礎結構必須支援附加值的支援屬性存放區。
XAML 中的附加屬性 (Property) 通常是透過屬性 (Attribute) 語法使用。 在屬性 (Attribute) 語法中,請使用格式 ownerType.propertyName
指定附加屬性 (Property)。
這有點像屬性元素的使用方式,不過這裡所指定的 ownerType
,絕對不能是設定附加屬性之物件元素的類型。
ownerType
是提供存取子方法的類型,是 XAML 處理器在取得或設定附加屬性值時的必要項目。
最常見的附加屬性案例,是啟用子元素回報屬性值給父元素。
以下範例說明 DockPanel.Dock 附加屬性。 DockPanel 類別會定義 DockPanel.Dock 的存取子,並擁有附加屬性。 DockPanel 類別也包含會逐一查看子元素的邏輯,並會特別檢查每個元素的 DockPanel.Dock 設定值。 若有找到值,就會在配置期間使用該值來放置子元素。 使用 DockPanel.Dock 附加屬性和這個置放功能,其實就是促成 DockPanel 類別的情況。
<DockPanel>
<Button DockPanel.Dock="Left" Width="100" Height="20">I am on the left</Button>
<Button DockPanel.Dock="Right" Width="100" Height="20">I am on the right</Button>
</DockPanel>
在 WPF 中,大多數或所有的附加屬性也會以相依性屬性的方式實作。 如需詳細資訊,請參閱附加屬性概觀。
附加事件使用類似的屬性 (Attribute) 語法 ownerType.eventName
格式。 就像非附加事件一樣,XAML 中附加事件的屬性 (Attribute) 值會指定在元素上處理事件時叫用的處理常式方法名稱。 WPF XAML 中的附加事件用法較不常見。 如需詳細資訊,請參閱 附加事件概觀。
基底類型
基礎 WPF XAML 及其 XAML 命名空間是類型的集合,對應於 CLR 物件和 XAML 的標記元素。 然而,並不是所有的類別都可以對應到元素。 ButtonBase 這類的抽象類別和某些非抽象的基底類別,是 CLR 物件模型中的繼承物。 基底類別 (包含抽象類別) 對於 XAML 開發而言仍然很重要,因為每個具象的 XAML 元素會繼承階層架構中某些基底類別的成員。 通常這些成員會包含可以設定為元素屬性 (Attribute) 的屬性 (Property),或是包含可以處理的事件。 FrameworkElement 是 WPF 架構層級的 WPF 實體基底 UI 類別。 設計 UI 時,您會使用各種圖案、面板、裝飾項目或控制項類別,這些都是衍生自 FrameworkElement。 相關的基底類別 FrameworkContentElement 使用可在 FrameworkElement 中故意鏡映 API 的 API,支援在流程配置展示方面運作良好的文件導向元素。 結合元素層級的屬性 (Attribute) 和 CLR 物件模型,提供您可以在大部分具象 XAML 元素上設定的通用屬性 (Property),而不用在意特定的 XAML 元素和其基礎類型。
安全性
XAML 是直接表示物件執行個體化和執行的標記語言。 因此,使用 XAML 建立的元素在與系統資源互動方面 (例如網路存取、檔案系統 IO),跟您的應用程式程式碼具有一樣的能力。 XAML 也和裝載應用程式一樣,有權存取系統資源。
WPF 中的程式碼存取安全性 (CAS)
和 .NET Framework 的差異是,適用於 .NET 的 WPF 不支援 CAS。 如需詳細資訊,請參閱程式碼存取安全性差異。
從程式碼載入 XAML
XAML 可以用來定義所有 UI,但有時候也比較適合在 XAML 中定義僅一部分的 UI。 這項功能可用來:
- 啟用部分自訂。
- UI 資訊的本機儲存體。
- 建立商務物件的模型。
這些案例的關鍵是 XamlReader 類別及其 Load 方法。 輸入是 XAML 檔案,而輸出則是代表所有物件執行階段樹狀結構並由該標記建立的物件。 接著,您可以將插入此物件,成為應用程式中已存在之其他物件的屬性。 只要屬性在內容模型中,且有最後顯示能力會通知執行引擎有新內容加入到應用程式,您就可以動態載入 XAML,輕鬆修改執行中的應用程式內容。