2013-12-11 46 views
16

加載XAML(或BAML)和接收根對象(例如Window)之間會發生什麼?XAML是如何在運行時解釋和執行的?

我腦子裏首先彈出的是Reflecton用來創建對象,設置它們的屬性等等。但也許我錯了?

也許有人可以解釋XAML/BAML在運行時如何被解析和執行,或者給出一個鏈接到一個好文章的解釋?

爲了使我的問題有點更清晰,讓我們討論的簡單的例子:

<Button Margin="10">OK</Button> 

所以,解析器看到一個按鈕對象需要被創建,它的Margin屬性必須被設置爲10,其內容必須設置爲「OK」。這是如何完成的?通過使用反射(加TypeConverters等)?

回答

25

您可能會注意到,在您的.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分析器使用其自己的類型系統,其中至少有兩個實現:

  1. 標準CLR類型系統基於反射和System.ComponentModel;
  2. 一個WPF類型的系統,通過包含對依賴項屬性和路由事件的特殊支持來擴展#1。

這是基於我的XAML語言規範的回憶,大約發生了什麼:

  1. 的XAML解析器遇到了Button類型,StartObject節點這(爲標準WPF命名空間映射)解析爲System.Windows.Controls.Button。這告訴解析器它需要創建一個Button對象的實例,它通過反射調用其默認構造函數來完成。
  2. 流中的下一個節點是StartMember節點,其成員名稱爲Margin。 WPF模式上下文的類型模型將將其解析爲Margin依賴項屬性。
  3. A Value下一個節點,它告訴解析器設置一個值"10"(一個字符串)。解析器發現屬性類型Thickness與字符串值不兼容。它會查詢它的類型系統以查看Margin屬性上是否存在[ValueSerializer]屬性,該屬性可用於轉換字符串;沒有這樣的屬性存在。它檢查屬性[TypeConverter]屬性;再次,它沒有發現。它在Thickness類型本身上查找[TypeConverter]屬性,並找到一個屬性,指示它使用ThicknessConverter將字符串值轉換爲Thickness。它這樣做。由於Margin是依賴項屬性,因此它使用SetValue() API設置屬性值;如果它是一個CLR屬性,它將使用反射或PropertyDescriptor
  4. EndMember節點告訴解析器結束屬性分配。
  5. 解析器遇到內容爲"OK"Value節點。解析器知道它正在構造一個複雜的對象,所以內容不能表示整個對象。它在Button及其超類型上尋找[ContentProperty]屬性;它在ContentControl上找到一個,它指示應該使用該值來設置Content屬性(將其解析爲相應的依賴項屬性)。 Contentobject,所以它直接指定string值(再次使用SetValue())。
  6. 下一個節點是EndObject,它告訴解析器它已完成對象的處理。

請注意,我使用術語「分析器」來簡化事情。事實上,在解析階段沒有發生這種情況(如果甚至存在「解析」階段)。您可能認爲「解析」階段只是構建XAML節點流。聲明對象的創建和/或填充實際上是通過將該流提供給XamlObjectWriter而發生的,XamlObjectWriter只是將XAML節點寫入對象(而不是XML文檔或BAML流)的XamlWriter的實現。在高層次上,只有兩件事情發生:

  1. XamlReader將某些東西轉換爲XAML節點流。
  2. XamlWriter將XAML節點流轉換爲某種東西。

在compled XAML資源的情況下,編譯時生成任務管用XamlXmlReader的輸出轉換成BamlWriter「編譯」的XAML。在運行時,將BamlReader的輸入傳送到XamlObjectWriter以創建或「修復」根對象。

一旦你理解了所有這些,就可以開始將XAML識別爲一種強大的序列化和持久性格式,而不僅僅是用於構建UI的語言。

+0

邁克,謝謝你的回答。你的附錄就是我所需要的。所以,在我們的微示例中,WPF引擎構造對象樹涉及大量使用反射,構造一個Button對象,找出使用哪個TypeConverter,構造TypeConverter,找出Margin是依賴屬性等等。 – WpfNewbie

+1

是的,XAML類型系統中有很多反思。 –

+0

很好的回答! – nawfal