您可能會注意到,在您的.xaml.cs
文件中,支持編譯的XAML文件的類會標記爲partial
類。 XAML構建任務會生成第二個.cs
文件,其中包含另一個部分類部分,其中包含IComponentConnector.InitializeComponent()
方法的實現,該方法由後面的代碼中的默認構造函數調用。這個方法基本上是通過XAML(它現在實際上是BAML形式)運行,並用它來「修復」新創建的對象,而不是從XAML源創建一個新對象,這就是如果你將使用XamlReader
加載或解析對象。
因此,當您實例化一個新編譯的XAML對象(例如,UserControl
)時,將執行構造函數中調用InitializeComponent()
之前的任何代碼。然後,在調用InitializeComponent()
期間處理在XAML文件中設置的所有屬性和事件處理程序,然後構造函數繼續。這可能對知道有用,因爲您可能希望確保在處理XAML文件之前或之後設置某些屬性。
至於XAML是如何解析的,它本質上是作爲表示屬性分配,對象聲明等的XAML節點流來讀取的,這些節點由服務在System.Xaml
中按順序執行。該節點流基於通用對象模型,該模型可能已經由BAML流,XML文檔(例如鬆散的.xaml
文件),另一個對象實例等構建而成.BAML比基於XML的格式更緊湊,通常解析速度更快。
附錄:在您添加的例子,你問解析器如何看待一個Button
對象需要創建和Margin
集。簡短的答案是:這取決於。具體而言,它取決於用於讀取XAML流的模式上下文。
的XAML分析器使用其自己的類型系統,其中至少有兩個實現:
- 標準CLR類型系統基於反射和
System.ComponentModel
;
- 一個WPF類型的系統,通過包含對依賴項屬性和路由事件的特殊支持來擴展#1。
這是基於我的XAML語言規範的回憶,大約發生了什麼:
- 的XAML解析器遇到了
Button
類型,StartObject
節點這(爲標準WPF命名空間映射)解析爲System.Windows.Controls.Button
。這告訴解析器它需要創建一個Button
對象的實例,它通過反射調用其默認構造函數來完成。
- 流中的下一個節點是
StartMember
節點,其成員名稱爲Margin
。 WPF模式上下文的類型模型將將其解析爲Margin
依賴項屬性。
- A
Value
下一個節點,它告訴解析器設置一個值"10"
(一個字符串)。解析器發現屬性類型Thickness
與字符串值不兼容。它會查詢它的類型系統以查看Margin
屬性上是否存在[ValueSerializer]
屬性,該屬性可用於轉換字符串;沒有這樣的屬性存在。它檢查屬性[TypeConverter]
屬性;再次,它沒有發現。它在Thickness
類型本身上查找[TypeConverter]
屬性,並找到一個屬性,指示它使用ThicknessConverter
將字符串值轉換爲Thickness
。它這樣做。由於Margin
是依賴項屬性,因此它使用SetValue()
API設置屬性值;如果它是一個CLR屬性,它將使用反射或PropertyDescriptor
。
EndMember
節點告訴解析器結束屬性分配。
- 解析器遇到內容爲
"OK"
的Value
節點。解析器知道它正在構造一個複雜的對象,所以內容不能表示整個對象。它在Button
及其超類型上尋找[ContentProperty]
屬性;它在ContentControl
上找到一個,它指示應該使用該值來設置Content
屬性(將其解析爲相應的依賴項屬性)。 Content
是object
,所以它直接指定string
值(再次使用SetValue()
)。
- 下一個節點是
EndObject
,它告訴解析器它已完成對象的處理。
請注意,我使用術語「分析器」來簡化事情。事實上,在解析階段沒有發生這種情況(如果甚至存在「解析」階段)。您可能認爲「解析」階段只是構建XAML節點流。聲明對象的創建和/或填充實際上是通過將該流提供給XamlObjectWriter
而發生的,XamlObjectWriter
只是將XAML節點寫入對象(而不是XML文檔或BAML流)的XamlWriter
的實現。在高層次上,只有兩件事情發生:
XamlReader
將某些東西轉換爲XAML節點流。
XamlWriter
將XAML節點流轉換爲某種東西。
在compled XAML資源的情況下,編譯時生成任務管用XamlXmlReader
的輸出轉換成BamlWriter
「編譯」的XAML。在運行時,將BamlReader
的輸入傳送到XamlObjectWriter
以創建或「修復」根對象。
一旦你理解了所有這些,就可以開始將XAML識別爲一種強大的序列化和持久性格式,而不僅僅是用於構建UI的語言。
邁克,謝謝你的回答。你的附錄就是我所需要的。所以,在我們的微示例中,WPF引擎構造對象樹涉及大量使用反射,構造一個Button對象,找出使用哪個TypeConverter,構造TypeConverter,找出Margin是依賴屬性等等。 – WpfNewbie
是的,XAML類型系統中有很多反思。 –
很好的回答! – nawfal