天天看點

XAML C# WPF

XAML定義

  XAML是一種相對簡單、通用的聲明式程式設計語言,它适合于建構和初始化.NET對象。

  XAML僅僅是一種使用.NET API的方式,把它與HTML、可伸縮向量圖形(SVG)或其他特定領域的格式或語言作比較是完全錯誤的。XAML由一些規則(告訴解析器和編譯器如何處理XML)和一些關鍵字組成,但它自己沒有任何有意義的元素。是以,如果在沒有WPF這樣的架構的基礎上讨論XAML,就如同在沒有.NET Framework的基礎上讨論C#一樣。

  XAML在WPF中扮演的角色通常是令人困惑的,是以第一件要搞清楚的事情是WPF和XAML可以獨立使用,它們并不是互相依賴的。雖然XAML最初是為WPF而設計,但它也可以應用于其他技術(如WF)。由于XAML的通用性,實際上可以把它應用于任何.NET技術。然而,是否在使用WPF時使用XAML是可選的,每一件XAML能做的事情完全可以由任何一種你喜歡的.NET語言來實作(但反過來則不行)。但是,由于XAML的諸多好處,很少會看到現實世界中使用WPF卻不使用XAML的情況。

元素和特性

  XAML規範定義了一些規則,用于把.NET命名空間、類型、屬性和事件映射為XML命名空間、元素和特性。以下面為例,它定義了一個WPF按鈕,跟另一段與之功能一緻的C#代碼比較一下:

  XAML:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK" Click="button_Click"/>      

  C#:

System.Windows.Controls.Button b = new System.Window.Controls.Button();
b.Content = "OK";
b.Click += new System.Windows.RoutedEventHandler(button_Click);      

  雖然這兩段代碼功能是相同的,但如果去除掉XAML中的Click特性,你可以很快地在IE浏覽器中檢視XAML,還會看到一個活生生的按鈕放在浏覽器視窗中。而C#代碼則必須要額外的代碼編譯方可使用。

  在XAML中定義一個XML元素(叫作對象元素)與在.NET中執行個體化一個對應的對象(總是使用預設的構造函數)是等價的。設定對象元素的一個特性(attribute),與設定一個同名屬性(property attribute,稱為屬性特性)或者為一個同名事件設定一個事件處理程式(也稱為事件特性),也是等價的。

生成和事件處理的順序

  在運作時(run-time)模式下,為任何一個XAML聲明的對象設定屬性之前,總要添加一些事件處理程式,這樣就可以讓某個事件在屬性被設定時被觸發,而不用擔心XAML使用特性的順序。

  至于多個屬性集或添加多個事件處理程式,它們總會遵照一定順序,即屬性特性和事件屬性是在對象元素中指定的。這一排序方式不會在實際應用中産生影響,因為.NET設計指南指出:類應該允許以任何順序設定屬性,添加事件處理程式也是如此。

命名空間

  比較上述XAML代碼示例和相應的C#代碼示例,最神秘的地方在于XAML命名空間(http://schemas.microsoft.com/winfx/2006/xaml/presentation)是如何被映射到.NET命名空間(System.Windows.Controls)上的。該映射及其他WPF命名空間的映射是在WPF程式集中寫死完成的,裡面有好幾個Xmlns-DefinitionAttribute自定義特性的執行個體。(在schemas.microsoft.com這個URL中不存在網頁,這僅僅是一個人為設定的字元串,就像其他命名空間一樣。)

  XAML檔案的根對象元素屬性指定至少一個XML命名空間,用于驗證自己和子元素。你可以(在根元素或子元素上)聲明額外的XML命名空間,但每一個命名空間下的辨別符都必須有一個唯一的字首。例如,WPF的XAML檔案都會使用第二個命名空間加上字首x(記作xmlns:x而不僅僅是xmlns):

  xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml

  這是XAML語言命名空間,用于映射System.Windows.Markup命名空間中的類型,而且它也定義了XAML編譯器或解析器中的一些特殊的指令。這些指令通常是作為XAML元素的特性出現的,是以,它們看上去像宿主元素的屬性,但實際上并不是如此。

  我們把http://schemas.microfost.com/winfx/2006/xaml/presentation作為預設(主要)命名空間,把http://schemas.microsoft.com/winfx/2006-/xaml作為次要命名空間。次要命名空間的字首是x,這僅僅是一個規則,就像C#檔案要以using System;指令開始一樣。你可以改寫原來那個XAML檔案,含義是相同的:

<WpfNamespace:Button xmlns:WpfNamespace="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK"/>      

  當然,從可讀性來講,在使用這些常見的命名空間的時候不需要字首(即原始的XML命名空間),其他一些命名空間則使用一個短字首。

屬性元素

  富建立是WPF的亮點之一,我們可以用Button來示範。你可以把任意内容放在Button裡面,不僅限于文本,如下所示(在Button中嵌入了一個簡單的方形來做一個VCR的停止按鈕):

System.Windows.Controls.Button b = new System.Windows.Controls.Button();
System.Windows.Shapes.Rectangle r = new System.Windows.Shapes.Rectangle();
r.Width = 40;
r.Height = 40;
r.Fill = System.Windows.Media.Brushes.Black;
b.Content = r;  //将按鈕中的内容設定為方格      

  Button的Content屬性是System.Object類型的,是以它很容易被設定到40*40的Rectangle對象。但如何才能在XAML中用屬性特性文法做相同的事呢?你該為Content屬性設定哪種字串才能完成C#中聲明的Rectangle功能呢?沒有這樣的字串,但XAML提供了一種替代的文法來設定複雜的屬性值,即屬性元素。如下所示:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Button.Content>
    <Rectangle Height="40" Width="40" Fill="Black"/>
</Button.Content>
</Button>      

  Content屬性被設定為一個XML元素而不是XML特性,Button.Content中的句點用于區分對象元素(object element)與屬性元素(property element)。它們總會以“類型名,屬性名TypeName.PropertyName”的形式出現,總會包含在“類型名”對象元素中,但它們沒有屬于自己的特性。

  屬性元素文法也可以用于簡單的屬性值。下面的Button使用特性設定了兩個屬性,它們是Content和Background:

<Button xmlns="http://schema.microsoft.com/winfx/2006/xaml/presentation" Content="OK" Background="White"/>      

  這等同于使用元素設定該Button的兩個相同的屬性:

XAML C# WPF
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Button.Content>
     OK 
</Button.Content>
<Button.Background>
     White
</Button.Background>
</Button>      
XAML C# WPF

  當然,在任何可以使用特性的地方使用特性更為便捷。

類型轉換器

  上例XAML檔案中的“white”是如何與C#中的System.Windows.Media.Brushes.White等價的呢?這個示例提供了一些如何使用字元串設定XAML屬性的細節,這些屬性的類型即不是System.String,也不是System.Object。在這種情況下,XAML解析器或編譯器必須尋找一個類型轉換器,該轉換器知道如何将一個字元串表達式轉換為一種想要的資料類型。WPF提供了許多常用資料類型的類型轉換器,如Brush、Color、FontWeight、Point等,它們都派生自Type-Converter的類(如BrushConverter、ColorConverter等),你也可以為自定義的資料類型寫類型轉換器。與XAML語言不同,類型轉換器通常支援不區分大小寫的字元串。

  如果沒有Brush類型轉換器,你就必須使用屬性元素文法來設定XAML中的Background屬性,如下所示:

XAML C# WPF
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK">
<Button.Background>
    <SolidColorBrush>
    <SolidColorBrush.Color>
        <Color A="255" R="255" G="255" B="255"/>
    </SolidColorBrush.Color>
    </SolidColorBrush>
</Button.Background>
</Button>      
XAML C# WPF

  由上可見,類型轉換器不僅增強了XAML的可讀性,也使一些本來不能被表達的概念得以表達。

  下面的代碼更精确地表達了運作時擷取和執行适合Brush的類型轉換器的過程:

System.Windows.Controls.Button b = new System.Windows.Controls.Button();
b.Content = "OK";
b.Background = (Brush)System.ComponentModel.TypeDescriptor.GetConverter(typeof(Brush)).ConvertFromInvariantString("White");      

标記擴充

  标記擴充就像類型轉換器一樣,可用于擴充XAML的表達能力。它們都可以在運作時計算字元串特性的值,并生成一個合适的基于字元串的對象。WPF有好幾個内建的标記擴充,你會發現它們都派生自本書最前面的内封中的MarkupExtension。

  與類型轉換器不同的是,标記擴充是通過XAML的顯式的、一緻的文法調用的,是以,标記擴充是最好的擴充XAML的方法。

  隻要特性值由花括号括起來,XAML編譯器或解析器就會把它認作一個标記擴充值而不是一個普通的字元串。下面的按鈕使用了3個不同的标記擴充類型,其中分别用到了3個不同的特性:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Background="{x:Null}"
Height="{x:Static SystemParameters.IconHeight}"
Content="{Binding Path=Height, RelativeSource={RelativeSource Self}}"/>      

  每個花括号中的第一個識别符是标記擴充類的名稱。按照慣例,這樣的類都以Extension字尾結尾,但在XAML中使用它時,可以不用該字尾。在上面例子中,NullExtension(即x:Null)和StaticExtension(即x:Static)是System.Windows.Markup命名空間的類,是以必須使用字首x來定位它們。Binding(沒有Extension字尾)是在System.Windows.Data命名空間下的,是以在預設的XML命名空間下就可以找到它。

  如果标記擴充支援,可使用逗号分隔的參數來指定它的值。

  定位參數(如本例中的SystemParameters.IconHeight)被作為字元串參數傳入擴充類的相應構造函數中。命名參數(如本例中的Path和RelativeSource)可用來在已構造好的擴充對象上設定相應名字的屬性。這些屬性的值可以是标記擴充值自己,也可以是文本值,它們可通過普通的類型轉換過程。你可能注意到設計和使用标記擴充與設計和使用自定義特性很相似,這是被有意設計的。

  在本例中,NullExtension允許設定Background筆刷為null。StaticExtension允許使用靜态屬性、字段、常量和枚舉值,而不使用XAML寫的寫死字面值。在這個例子中,Button的高度是遵循作業系統目前的圖示高度設定的,這一設定可通過System.Windows.SystemParameters類的IconHeight靜态字段獲得。Binding可以把Content設定為與它的Height屬性相同的值。

  如果你需要設定一個屬性特性值為字面字元串(以左花括号開始),就必須将其轉義,我們可通過在其前面增加一對空花括号來實作,如:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
Content="{}{This is not a markup extension!}"/>      

  此外,也可以使用屬性元素文法,因為花括号在上下文中不會有特殊的意義:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    {This is not a markup extension}
</Button>      

  因為标記擴充是有預設構造函數的類,它們可以與屬性元素文法一起使用,如下例:

XAML C# WPF
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button.Background>
    <x:Null/>
</Button.Background>
<Button.Height>
    <x:Static Member="SystemParameters.IconHeight"/>
</Button.Height>
<Button.Content>
    <Binding Path="Height">
    <Binding.RelativeSource>
        <RelativeSource Mode="Self"/>
    </Binding.RelativeSource>
    </Binding>
</Button.Content>
</Button>      
XAML C# WPF

  該轉換之是以可以執行是因為這些标記擴充都有與形參化的構造函數的實參(使用屬性特性文法的定位實參)對應的屬性。例如,StaticExtension有一個Member屬性與之前傳入到開參化構造函數中的實參意思是一樣的,RelativeSource有一個對應于構造函數實參的Mode屬性。

  由于标記擴充完成的實際工作對于每個擴充都是不同的。如下面的C#代碼與使用NullExtension、StaticExtension和Binding的基于XAML表示的按鈕是一個意思:

XAML C# WPF
System.Windows.Controls.Button b = new System.Windows.Controls.Button();
//設定Background
b.Background = null;
//設定Height
b.Height = System.Windows.SystemParameters.IconHeight;
//設定Content
System.Windows.Data.Binding binding = new System.Windows.Data.Binding();
binding.Path = new System.Windows.PropertyPath("Height");
binding.RelativeSource = System.Windows.Data.RelativeSource.Self;
b.SetBinding(System.Windows.Controls.Button.ContentProperty, binding);      
XAML C# WPF

  盡管如此,這裡的代碼與XAML解析器或編譯器使用的機制是不同的,解析器和編譯器是依靠每個标記擴充在運作時設定合适的值(本質上是通過調用每個類的ProvideValue方法來實作的)。與這一機制完全對應的過程式代碼通常很複雜。

對象元素的子元素

  XAML檔案就像所有的XML檔案一樣,必須有一個單獨的根對象元素。對象元素是可以支援子對象元素的。一個對象元素可以有3種類型的子元素:一個内容屬性值,集合項,或一個能夠通過類型轉換到它的父元素的值。

内容屬性

  大多數WPF類(通過定制特性)指定了一個屬性,該屬性可以被設定為XML元素中的任何内容。這個屬性叫作内容屬性,它确實是一個讓XAML呈現變得更輕便簡單的捷徑。從某種意義上講,這些内容屬性有點像VB中的預設屬性。Button中的Content屬性就是這樣指定的,如:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK"/>      

  可以被重寫為:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
OK
</Button>      

  還有更複雜的方式:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Button.Content>
    <Rectangle Height="40" Width="40" Fill="Black"/>
</Button.Content>
</Button>      

  可以被重寫為:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <Rectangle Height="40" Width="40" Fill="Black"/>
</Button>      

集合項

  XAML允許将項添加到支援索引的兩種類型的集合中:List和Dictionary。

List

  List是實作了System.Collection.IList接口的集合,如System.Collections.ArrayList和許多WPF定義的集合類都是List。如,下面的XAML向ListBox添加了兩個項,它的Items屬性是實作了IList的ItemCollection類型:

<ListBox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> 
<ListBox.Items>
     <ListBoxItem Content="Item 1"/>
     <ListBoxItem Content="Item 2"/> 
</ListBox.Items> 
</ListBox>      

  因為Items是ListBox的内容屬性,可以進一步簡化:

<ListBox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <ListBoxItem Content="Item 1"/>
    <ListBoxItem Content="Item 2"/>
</ListBox>      

Dictionary

  System.Windows.ResourceDictionary是WPF中的一個常用的集合類型,它實作了System.Collections.IDictionary接口,能夠支援在過程式代碼中添加、移除枚舉鍵/值對。下面的XAML添加了兩個Color對象到一個ResourceDictionary中。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Color x:Key="1" A="255" R="255" G="255" B="255"/>
    <Color x:Key="2" A="0" R="0" G="0" B="0"/>
</ResourceDictionary>      

  注意,在帶有x:Key的XAML中指定的值總是被作為字元串處理的,除非使用标記擴充,但不會嘗試使用類型轉換。

  XAML是設計用來與.NET類型系統一起工作的,你可以在其中使用任何類型的.NET對象,也可以使用自己定義的對象。但對象必須以“友好聲明”的方式進行設計。如果一個類沒有預設構造函數,也沒有提供有用的執行個體屬性,那麼它在XAML中是無法直接使用的。

  WPF程式集都被加上了XmlnsDefinitionAttribute屬性,這樣可以将.NET命名空間映射為XAML檔案中的XML命名空間,但對于那個不是專門為XAML設計的程式集又該如何處理呢?它們的類型仍然可以使用,隻需要一個特殊的指令作為XML命名空間就可以了。如下例:

System.Collections.Hashtable h = new System.Collections.Hashtable();
h.Add("key1", 1);
h.Add("key2", 2);      

  以上代碼在XAML中表示為:

<collections:Hashtable xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <sys:Int32 x:Key="key1">1</sys:Int32>
    <sys:Int32 x:Key="key2">2</sys:Int32>
</collections:Hashtable>      

  clr-namespace标記允許直接在XAML中放入一個.NET命名空間。

  為了避免混淆,在轉換子元素時,任何一個有效的XAML解析器或編譯器必須遵循下面的規則:

  1. 如果該類型實作了IList接口,就為每個子元素調用IList.Add。
  2. 否則,如果該類型實作了IDictionary,就為每個子元素調用IDictionary.Add,在該值的鍵和元素中使用x:Key特性值。
  3. 否則,如果父元素支援内容屬性(由System.Windows.Markup.ContentPropertyAttribute表示),而且子元素的類型與該内容屬性是相容的,就把子元素作為它的值。
  4. 否則,如果子對象是普通文本,且有類型轉換器将子對象轉換為父類型(沒有在父元素上設定屬性),則把子元素作為類型轉換器的輸入,将輸出作為父對象的執行個體。
  5. 其他情況下則抛出錯誤。

編譯:将XAML與過程式代碼混合使用

  大多數WPF應用程式是XAML與過程式代碼的混合體。

在運作時加載和解析XAML

  WPF的運作時XAML解析器公開為兩個類,它們都位于System.Windows.Markup命名空間中:XamlReader和XamlWriter。XamlReader包含了一些對靜态Load方法的重載,而XamlWriter包含了一些對靜态Save方法的重載。是以,用任何一種.NET語言寫的程式都可以在運作時依賴XAML,而不用程式員付出太多努力。

XamlReader

  XamlReader.Load方法的設定将解析XAML,建立合适的.NET對象,然後傳回一個根元素的執行個體。是以,如果在目前目錄下有一個XAML檔案叫作MyWindow-.xaml,它包含了一個Window對象作為根結點,那麼可以使用下面的代碼來加載和獲得Window對象。

Window window = null;
using(FileStream fs = new FileStream("MyWindow.xaml", FileMode.Open, FileAccess.Read))
{
    //獲得根元素,該元素是一個Window對象
    Window = (Window)XamlReader.Load(fs);
}      

  在Load傳回之後,整個XAML檔案的對象層級将在記憶體中被執行個體化,是以就不再需要XAML檔案了。退出using代碼塊後,FileSteam将被立即關閉。由于可向XamlReader傳入一個任意的Stream(或使用另一個重載來傳入System.Xml.XmlReader對象),是以有許多可選擇的方式來獲得XAML的内容。

  XamlReader也定義了LoadAsync執行個體方法用于異步加載和解析XAML内容。在加載大檔案或網絡檔案時,可使用LoadAsync保持使用者界面處于響應狀态。CancelAsync方法用于停止處理,LoadCompleted事件可讓我們知道處理何時完成。

  既然已有一個根元素的執行個體存在,就可利用适當的内容屬性或集合屬性來獲得子元素。下面的代碼假設Window有一個類行為StackPanel的子元素,Stack-Panel的第5個子對象是一個OK Button。

XAML C# WPF
Window window = null;
using(FileStream fs = new FileStream("MyWindow.xaml"), FileMode.Open, FileAccess.Read))
{
    //獲得根元素,該元素是一個Window對象
    window = (Window)XamlReader.Load(fs);
}
//通過(寫死知識)周遊子元素擷取OK按鈕
StackPanel panel = (StackPanel)window.Content;
Button okButton = (Button)panel.Children[4];      
XAML C# WPF

  有了這個Button的引用,就可以做任何想做的事:設定額外的屬性,添加事件處理程式,或執行一些無法用XAML完成的動作。

  但使用寫死索引和其他關于使用者界面結構假設的代碼并不能讓人滿意。XAML支援元素命名,這樣就可以從過程式代碼中找到這些元素并放心地使用它們。

命名XAML元素

  XAML語言命名空間有一個Name關鍵字,它是用來給元素命名的。示例如下:

<Button x:Name="okButton">OK</Button>      

  上例代碼可改如下:

XAML C# WPF
Window window = null;
using(FileStream fs = new FileStream("MyWindow.xaml"), FileMode.Open, FileAccess.Read)) 
{
     //獲得根元素,該元素是一個Window對象
    window = (Window)XamlReader.Load(fs); 
} 
//通過按鈕的名稱獲得OK按鈕Button 
okButton = (Button)window.FindName("okButton");      
XAML C# WPF

  FindName并不僅僅在Window類中存在,在FrameworkElement、FrameworkContentElement及許多重要的WPF類的基類中也有FindName的定義。

編譯XAML

  XAML編譯包括三項事件:

  1. 将一個XAML檔案轉換為一種特殊的二進制格式。
  2. 将轉換好的内容作為二進制資源嵌入到正在被建立的程式集中。
  3. 執行連結操作,将XAML和過程式代碼自動連接配接起來。

  如果你不在乎将XAML檔案和過程式代碼融合,那麼隻需把它添加到VS的WPF項目中來,并用界面中的Build動作來完成編譯即可。但如果要編譯一個XAML檔案并将它與過程式代碼混合,第一步要做的就是為XAML檔案的根元素指定一個子類,可以用XAML語言命名空間中的Class關鍵字來完成。例如:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyNamespace.MyWindow">
...
</Window>      

  在一個獨立的源檔案中(但是在同一個項目中),可以一個子類,并添加任何想添加的成員:

XAML C# WPF
namespace MyNamespace
{
    partial class MyWindow : Window
    {
        public MyWindow
        {
            //一定要調用,這樣才能加載XAML定義的内容
            InitializeComponent();
            ...
        }
        Any other members can go here...
    }
}      
XAML C# WPF

  通常我們把這樣的檔案叫作代碼隐藏檔案。如果你引用XAML中的任何一個事件處理程式(通過事件特性,如Button的Click特性),這裡就是我們定義這些事件處理程式的地方。

  當在VS中建立一個基于WPF的C#或VB項目,或當使用“Add New Item...”來添加某WPF項目時,VS會自動建立一個XAML檔案,并把x:Class作為根元素,同時建立一個具有部分類定義的代碼隐藏源檔案,最後把兩者連接配接起來,這樣代碼建構(build)才能順利進行。

BAML

  BAML是Binary Application Markup Language的縮寫,意思是二進制應用程式标記語言,它其實是被解析、标記化,最後轉換為二進制形式的XAML。雖然大塊的XAML代碼可以被表示為過程式代碼,但XAML到BAML的編譯過程不會生成過程源代碼。是以,BAML不像MSIL,它是一個壓縮的聲明格式,比加載和解析普通的XAML檔案快,且比普通XAML檔案要小。BAML僅僅是XAML編譯過程的詳細實作,沒有任何直接公開的方法,在未來可能會被一些其他東西所取代。

生成的源代碼

  x:Class隻能在要編譯的XAML檔案中使用。但在沒有x:Class的情況下,編譯XAML檔案也是沒有問題的。這意味着沒有對應的代碼隐藏檔案,是以不能使用任何需要過程式代碼才能實作的特性。

  每個生成的源檔案中包含了一個由根對象元素中的x:Class指定的類的部分類定義。XAML檔案中的每個已命名的元素在該部分類中都有一個成員(預設是私有的),這些成員的名稱就是元素名稱。其中還有一個InitializeComponent方法用于完成一大堆煩人的工作。

BAML可以反編譯為XAML嗎?

  可以,無論怎麼聲明,任何一個公司的.NET類執行個體都可以被序列化為XAML。第一個步驟是擷取一個執行個體,這個執行個體是用來作為根對象的。如果你還沒有這個對象,可以調用靜态的System.Windows.Application.LoadComponent方法,如下所示:

System.Uri uri = new System.Uri("MyWindow.xaml", System.UriKind.Relative);
Window window = (Window)Application.LoadComponent(uri);      

  由URI指定的名稱并不要求實體上存在一個獨立的xaml檔案。當指定了一個合适的URI後,LoadComponent可以自動獲得作為資源嵌入的BAML。實際上,VS自動生成的InitializeComponent方法就是調用Application.LoadComponent來加載嵌入的BAML。

  獲得根元素的執行個體後,可以使用System.Windows.Markup.XamlWrite類來獲得根元素的XAML表示。XamlWriter包含了5個靜态Save方法的重載,是最簡單的傳回一個适當XAML字元串的方法,通過傳入一個對象執行個體來實作。如:

string xaml = XamlWriter.Save(window);      

XAML關鍵字

  XAML語言的命名空間(http://schemas.microsoft.com/winfx/2006/xaml)定義了一批XAML編譯器或解析器必須特殊處理的關鍵字。它們主要控制元素如何被提供給過程式代碼,但即使沒有過程式代碼,有一些關鍵字還是有用的。如Key、Name、Class、Subclass和Code。

繼續閱讀