本主題定義用來描述可擴展應用程序標記語言 (XAML) 語法的各個元素的術語這些術語將在本軟件開發工具包 (SDK) 的其余部分中經常用到本主題擴展了 XAML 概述中所介紹的基本術語
XAML 語法術語的起源
此處定義的 XAML 語法術語在 XAML 語言規范中也有定義或引用XAML 是一種基於 XML 且遵循 XML 結構規則的語言其中的術語共享自或基於描述 XML 語言或 XML 文檔對象模型 (DOM) 時的常用術語
對象元素語法
對象元素語法是一種 XAML 標記語法它通過聲明 XML 元素來實例化公共語言運行庫 (CLR) 類或結構此語法與其他標記語言(例如 HTML)的元素語法相似對象元素語法以左尖括號 (<) 開頭其後緊跟正進行實例化的類或結構的類型名稱類型名稱後面可以有零個或多個空格對於對象元素還可以聲明零個或多個屬性並用一個或多個空格來分隔每個屬性名=值對最後必須存在下列一種情況
元素和標記必須用正斜槓 (/) 和緊跟的右尖括號 (>) 結尾
開始標記必須以右尖括號 (>) 結尾其他對象元素屬性元素或內部文本可以跟在開始標記後面對象元素還必須存在等效的結束標記並與其他開始標記/結束標記對形成正確的嵌套和平衡
例如下面的示例是一個對象元素語法該語法實例化 Button 類的一個新實例而且還指定了一個 Name 屬性及其值
下面的示例是一個還包括可擴展應用程序標記語言 (XAML) 內容屬性語法的對象元素語法其中包含的內部文本將用來設置 TextBox 可擴展應用程序標記語言 (XAML) 內容屬性 Text
屬性語法
屬性語法是一種 XAML 標記語法該語法通過針對元素聲明屬性 (Attribute) 來設置屬性 (Property) 值或者命名事件的事件處理程序元素總是通過對象元素語法來聲明屬性名必須與屬性或事件的 CLR 成員名稱相匹配屬性名後面是賦值運算符 (=)屬性值必須是一個用雙引號 () 引起來的字符串
為了能夠通過屬性語法進行設置屬性必須是公共的可讀寫的而且必須具有一個可以由 XAML 處理器實例化或引用的屬性值類型對於事件來說事件必須是公共的而且必須具有一個公共委托屬性或事件必須是由包含對象元素實例化的類或結構的成員
屬性值由下面的操作之一按照如下處理順序進行填充
如果 XAML 處理器遇到一個大括號或者遇到一個從 MarkupExtension 派生的對象元素則將首先計算所引用的標記擴展(而不是將該擴展作為字符串來處理)而且將使用由標記擴展返回的對象在許多情況下由標記擴展返回的對象將是對現有對象的引用或者是一個將計算推遲到運行時的表達式而不是一個新對象
如果該屬性 (Property) 是用指定的 TypeConverter 聲明的或者該屬性 (Property) 的值類型是用屬性 (Attribute) 化 TypeConverter 聲明的則該屬性 (Attribute) 的字符串值將作為轉換輸入提交到類型轉換器該轉換器將返回一個新的對象實例
如果沒有 TypeConverter則將嘗試直接轉換為屬性類型最後一個級別是直接在基元類型之間轉換或者在枚舉中檢查名稱(這將返回匹配的值)
例如在使用上面所顯示的標記時可以使用下面的屬性 (Attribute) 語法示例為
Name 屬性 (Property) 賦予字符串值
Name 屬性是 Button 類的成員表的成員Button 是用來定義 Name 的 FrameworkElement 類的派生類
屬性值的處理
包含在左引號和右引號之間的字符串值是由 XAML 處理器處理的對於屬性來說默認處理行為是由基礎 CLR 屬性的類型確定的如果該屬性 (Property) 是基元類型則會基於字符串到相關基元類型的隱式轉換來賦予屬性 (Attribute) 值如果該屬性是一個枚舉則字符串會被視為由該枚舉定義的名稱而且將從枚舉中返回匹配的值如果該屬性 (Property) 既不是基元類型又不是枚舉則屬性 (Attribute) 值必須由針對該屬性 (Property) 本身或者目標類型聲明的類型轉換器來處理類型轉換器必須提供一個能夠接受字符串的轉換機制該轉換機制必須生成基礎 CLR 屬性類型的實例還可以通過標記擴展來推遲轉換步驟
枚舉屬性值
XAML 中的枚舉值由 Enum 結構的本機方法在內部處理
對於無標志的枚舉值本機行為是處理屬性值的字符串並將它解析為某個枚舉值您不必像在代碼中那樣指定格式為枚舉值 的枚舉而是僅指定值枚舉 將從所設置屬性的類型推斷如果您指定格式為枚舉值 的屬性它將無法正確解析
對於按標志枚舉該行為基於 Enum::Parse 方法您可以通過用逗號分隔每個值來為按標志枚舉指定多個值但是您不能合並不按標志的枚舉值例如不能試圖使用逗號語法來創建作用於無標志枚舉多個條件的 Trigger
在 WPF 中能夠支持 XAML 中可設置屬性的按標志枚舉極為罕見但是StyleSimulations 就是這樣的一個枚舉例如可以使用逗號分隔的按標志屬性語法來修改在 Glyphs 類的Remarks(備注)部分中提供的示例StyleSimulations = BoldSimulation 可能會變成 StyleSimulations = BoldSimulationItalicSimulationKeyBinding::Modifiers 是另一個屬性在該屬性中可以指定多個枚舉值但是此屬性是一個特例因為 ModifierKeys 枚舉支持其自身的類型轉換器修飾符的類型轉換器使用加號 (+) 而不是逗號 () 作為分隔符因此在標記中支持用更傳統的語法來表示組合鍵(如Ctrl+Alt)
屬性引用和事件成員名稱引用
在指定屬性 (Attribute) 時可以引用您已經為包含對象元素實例化的 CLR 類型的成員表中存在的任何屬性 (Property) 或事件
或者可以獨立於包含對象元素來引用附加屬性或附加事件
對於可通過默認命名空間訪問的任何對象中的任何事件還可以通過使用類型名事件 部分限定名來命名此語法支持為路由事件附加處理程序在路由事件中處理程序旨在處理子元素中的事件路由但是父元素在其成員表中並不擁有該事件此語法與附加事件語法相似但此處的事件不是真正的附加事件相反您引用的是具有限定名稱的事件
屬性 (Property) 名有時作為屬性 (Attribute) 值提供而不是作為屬性 (Attribute) 名提供屬性 (Property) 名還可以包括限定符例如以所有者類型依賴項屬性名稱 格式指定的屬性在 XAML 中編寫樣式或模板時此情況較為常見以屬性 (Attribute) 值形式提供的屬性 (Property) 名具有不同的處理規則這些規則由所設置的屬性 (Property) 類型以及某些上下文因素(如樣式或模板是否具有目標類型)來控制
當屬性 (Attribute) 值描述屬性 (Property) 之間的關系時也可以使用屬性 (Property) 名此功能可用於數據綁定和演示圖板目標而且由 PropertyPath 類及其類型轉換器啟用
屬性元素語法
屬性元素語法是一種與基本 XML 語法稍有偏離的語法在 XML 中屬性值是一個實際的字符串唯一可能的變化是使用除 UTF 之外的哪種字符串編碼格式在 XAML 中可以指定其他對象元素作為屬性值此功能由屬性元素語法來啟用不將屬性 (Property) 指定為元素標記中的一個屬性 (Attribute)而是使用元素的開始標記指定格式為元素類型名稱屬性名 的屬性 (Property)再指定屬性 (Property) 值然後結束屬性元素
具體而言該語法以左尖括號 (<) 開頭其後緊跟包含屬性元素語法的類或結構的類型名稱類型名稱後面緊跟一個點 ()再後面是必須在指定類型的成員表中存在的屬性名最後面是一個右尖括號 (>)要賦給屬性的值包含在相應的屬性元素中通常值作為一個或多個對象元素提供因為將對象指定為值正是屬性元素語法應當實現的方案最後必須提供一個等效的結束標記來指定同一個元素類型名稱屬性名稱 組合並與其他元素標記對形成正確的嵌套和平衡例如下面的屬性元素語法針對的是 Button 的 ContextMenu 屬性
值也可以作為內部文本提供但是只有當指定的屬性類型是基元值類型(如 String)或者是指定了名稱的枚舉時才能這樣做這兩個用法不太常見因為這兩種情況都還支持屬性語法用字符串填充屬性元素的一個方案是對於不是 XAML 內容屬性但是仍用於表示 UI 文本的屬性UI 文本中必須出現特定的空白元素(如換行符)屬性 (Attribute) 語法不能保留換行符但是屬性 (Property) 元素語法可以保留換行符不過前提是用來保留大量空白的功能處於活動狀態
屬性元素不屬於邏輯樹它不是由實例支持的元素而只是一個用來設置屬性的特定語法
集合類型的屬性元素語法
XAML 規范要求所實現的 XAML 處理器能夠標識值類型是集合的屬性WPF 實現基於托管代碼它的 XAML 處理器通過下列操作之一來標識集合類型
實現 IList
實現 IDictionary
從 Array 派生
如果屬性的類型是集合則不必在標記中指定所推斷的集合類型相反應當成為集合中項的元素將被指定為集合類型屬性元素的一個或多個子元素在加載每個這樣的項並通過調用隱式集合的 Add 方法將其添加到集合的過程中會將該項計算為一個對象例如Style 的 Triggers 屬性采用專用集合類型 TriggerCollection但是在標記中不必實例化 TriggerCollection而是需要在 StyleTriggers 屬性元素中指定一個或多個 Trigger 項作為元素其中 Trigger(或派生類)是一個類型應當作為隱式強類型 TriggerCollection 的項類型
屬性可以既是一個集合類型又是該類型和派生類型的 XAML 內容屬性
隱式集合元素會在邏輯樹中創建一個成員即使它在標記中不顯示為元素也是如此通常所擁有類型的構造函數針對作為其屬性之一的集合執行實例化這會將該集合添加到樹中
說明
由 WPF XAML 處理器執行的集合檢測功能不支持泛型列表和字典接口(IList<(Of <(T>)>) 和 IDictionary<(Of <(TKey TValue>)>))但是可以將 List<(Of <(T>)>) 類用作基類(因為它直接實現 IList)或者將 Dictionary<(Of <(TKey TValue>)>) 用作基類(因為它直接實現 IDictionary)
XAML 內容語法
XAML 內容語法僅在將 ContentPropertyAttribute 指定為其類聲明一部分的類上啟用ContentPropertyAttribute 需要一個按名稱指定屬性的參數而該屬性名稱被定義為這種類型元素(包括派生的類)的內容屬性為此指定的屬性是元素的 XAML 內容屬性在由 XAML 處理器處理時在元素的開始標記和結束標記之間找到的任何子元素或內部文本將被指定為該 XAML 內容屬性的值元素的屬性元素標記不按照這種方式賦值它們是先進行處理而且不被視為內容
正如對於任何其他屬性一樣對象的 XAML 內容屬性將屬於特定類型該類型可以是 Object 類型該內容屬性的類型可幫助定義對象的內容模型例如鑒於任何對象都可以變為內容Object 的類型是松散的但是即使這種松散類型也要求內容必須是單個對象該單個對象可以是集合對象
但是即便如此也只能將一個這樣的集合對象指定為內容
特定類型的內容模型在該類型的類頁面上進行描述或者編寫成類型系列的單獨概念性主題中並與每個相關的類型引用建立鏈接
集合類型的內容語法
為了接受多個對象元素(或內部文本)作為內容內容屬性的類型必須是明確的集合類型與集合類型的屬性元素語法相似XAML 處理器必須標識作為集合類型的類型如果某個元素具有 XAML 內容屬性則該 XAML 內容屬性的類型是集合不必在標記中將隱含集合類型指定為對象元素也不必將 XAML 內容屬性指定為屬性元素因此標記中明顯的內容模型現在可以將多個子元素作為指定為內容下面是 Panel 子類的內容語法所有的 Panel 派生類都建立要成為 Children 的 XAML 內容屬性這需要一個類型為 UIElementCollection 的值
請注意標記中既不需要 Children 的屬性元素也不需要 UIElementCollection 的元素這是 XAML 的設計特征其目的在於使用直接的父子元素關系將那些用來定義 UI 的遞歸包含的元素更直觀地表示為嵌套元素樹而不必對屬性元素標記或集合對象進行外部干預實際上按照設計UIElementCollection 在標記中不能指定為對象元素由於 UIElementCollection 唯一的用途就是作為隱式集合因此它不公開公共的默認構造函數因此不能實例化為對象元素
在具有內容屬性的對象中混合使用屬性元素和對象元素
XAML 規范聲明 XAML 處理器可以進行如下強制用來填充某個對象元素中 XAML 內容屬性的對象元素必須是連續的而且不得混合使用對於混合使用屬性元素和內容的這一限制是由 WPF XAML 處理器強制的
可以將子對象元素作為某個對象元素中的第一個直接標記然後可以引入屬性元素也可以指定一個或多個屬性元素接著指定內容然後指定多個屬性元素但是一旦內容後面跟有屬性元素您就不能進一步引入任何內容而只能引入其他屬性元素
這個內容/屬性元素順序要求不適用於用作內容的內部文本然而這仍然是使內部文本保持連續的不錯的標記樣式原因是如果屬性元素與內部文本交錯分布則很難直觀地檢測標記中的大量空白
附加屬性
附加屬性是 XAML 中引入的一個編程概念借此屬性可以由類型擁有和定義但可以在任何元素上設置附加屬性所面向的主要方案就是允許元素樹中的子元素向父元素報告信息而不要求使用在所有的元素之間廣泛共享的對象模型相反附加屬性可以由任何父元素用來向子元素報告信息
附加屬性使用的語法在表面上與屬性元素語法非常相似因為您還需要指定類型名屬性名 組合二者有兩個重要的差異
即使在通過屬性語法設置附加屬性時也可以使用類型名屬性名 組合只有附加屬性 (Property) 才要求屬性 (Attribute) 語法中使用限定屬性 (Property) 名
對於附加屬性還可以使用屬性元素語法但是對於典型的屬性元素語法您指定的類型名 是包含屬性元素的對象元素如果您引用的是附加屬性則類型名 是用來定義附加屬性的類而不是包含對象元素
附加事件
附加事件是 XAML 中引入的另一個編程概念事件可以由類型定義但是處理程序可以附加到任何對象上用來定義附加事件的類型通常是用來定義服務的靜態類型這些附加事件有時由用來公開服務的類型中的路由事件別名公開附加事件的處理程序是通過屬性語法指定的正如對於附加事件一樣可以擴展附加事件的屬性語法以便允許使用類型名事件名其中類型名 是為附加事件基礎結構提供 Add 和 Remove 事件處理程序訪問器的類事件名 是事件名稱
XML 命名空間
上面的所有語法示例均未指定默認命名空間以外的命名空間在典型的 WPF 應用程序中默認命名空間被指定為 WPF 命名空間您可以指定默認命名空間以外的命名空間而且仍使用實質上同類的語法但是只要命名了無法在默認命名空間中訪問的類該類的名稱就必須以用來映射對應 CLR 命名空間的 XML 命名空間的前綴作為開頭例如 是一種用來實例化 MyElement 類的實例的對象元素語法其中包含該類的 CLR 命名空間(可能還有包含該命名空間的外部程序集)以前映射到 custom 前綴
標記擴展
XAML 定義了一個標記擴展編程實體該實體允許從 XAML 處理器對屬性或對象元素的常規處理中進行轉義將該處理轉給支持類WPF 對 XAML 處理器的實現將 MarkupExtension 抽象類用作由 WPF 支持的所有標記擴展的基礎在使用屬性語法時用來標識 XAML 處理器的標記擴展的字符是左大括號 ({)其後是右大括號 (}) 以外的任何字符左大括號後面的第一個字符串必須引用用來提供特定擴展行為的類如果子字符串Extension是實際類名的一部分則該引用可以省略這個子字符串該類後面可能會出現一個空格該空格後面的每個字符都可以由所實現的擴展用作輸入直到遇到右大括號在使用屬性語法時WPF 中標記擴展的主要用途是提供一種方法來引用其他已經存在的對象或者將引用轉給將在運行時計算的對象例如可以指定用 {Binding} 標記擴展來代替給定的屬性通常將使用的值類型從而完成簡單的數據綁定對於無法以其他方式使用屬性 (Attribute) 語法的屬性 (Property)許多標記擴展都允許使用屬性 (Attribute) 語法例如Style 對象是一個相對復雜的引用類型其中包含幾個其他屬性每個屬性都還采用 byref 對象(而非基元)但是樣式通常作為資源來創建之後將通過請求資源的兩個標記擴展之一來引用該擴展將對屬性 (Property) 值的計算推遲到資源查找時允許在屬性 (Attribute) 語法中提供 Style 屬性 (Property) 的值並采用 Style 類型如下所示
在這裡StaticResource 用來標識 StaticResourceExtension 類該類提供標記擴展實現下一個字符串 MyStyle 用作非默認 StaticResourceExtension 構造函數的輸入在該構造函數中從擴展字符串提取的參數用來聲明所請求的 ResourceKeyMyStyle 應當是定義為資源的 Style 的 x:Key 屬性 值StaticResource 標記擴展用法要求使用該資源在加載時通過靜態資源查找邏輯來提供 Style 屬性值
可選的和不建議的 XAML 用法
屬性元素的可選用法
屬性元素的可選用法包括具體地拼出由 XAML 處理器視為隱式的元素內容屬性例如當您聲明 Menu 的內容時可以選擇將 Menu 的 Items 集合顯式聲明為
屬性元素標記並將每個 MenuItem 放在 中而不是使用隱式的 XAML 處理器行為(即Menu 的所有子元素都必須是 MenuItem 而且放在 Items 集合中)有時這個可選用法可以幫助以可視方式闡明標記中所表示的對象結構
或者屬性元素的隱式用法有時可以避免使用在技術上具有功能但是在視覺上容易引起混淆(如在屬性值中嵌套標記擴展)的標記
mberName 全限定屬性
使用屬性的類型名成員名 格式實際上比僅僅使用路由事件的情況更為普遍但是在其他應用程序中如果只是為了實現標記樣式和可讀性則該格式是多余的您應當避免使用它在下面的示例中對 Background 屬性的三個引用是完全等效的
ButtonBackground 之所以適用是因為在 Button 上對於該屬性的查找是成功的(Background 是從 Control 繼承的)而且 Button 是對象元素的類或者是基類ControlBackground 之所以適用是因為 Control 類實際上定義 Background而且 Control 是一個 Button 基類
但是下面的類型名成員名 格式示例並不適用因此顯示為已注釋掉
Label 是 Control 的另一個派生類而且如果在 Label 對象元素中指定了 LabelBackground則該用法將適用但是由於 Label 不是 Button 的類或基類因此指定的 XAML 處理器行為是隨後以附加屬性形式處理 LabelBackgroundLabelBackground 不是附加屬性因此該用法將失敗
mberName 屬性元素
與類型名成員名 格式如何適用於屬性語法相似基類型名稱成員名 語法適用於屬性元素語法例如下面的語法適用
在這裡即使屬性元素包含在 Button 中屬性元素也會以 ControlBackground 形式提供
但是正如屬性的類型名成員名 格式一樣基類型名稱成員名 在標記中是很差的樣式您應當避免將其用於設置樣式
From:http://tw.wingwit.com/Article/program/net/201311/12698.html