前言
XAML是微軟推出的一種宣告式標記語言采用XML的格式讓開發人員設計應用程序編程接口在微軟近期推出的各種開發平台例如WPFSilverlightWP甚至Win的Metro style app開發上都可以看到XAML的身影XAML可以這麼的神奇的跨平台運作是因為XAML不涉足執行平台的運作機制…等等只單純的依照開發人員的設計建立對應的對象讓執行平台使用例如
XAML范例
<phone:PhoneApplicationPage
x:Class=XamlSampleMainPage
xmlns=
xmlns:x=
xmlns:phone=clrnamespace:MicrosoftPhoneControls;assembly=MicrosoftPhone
xmlns:d=
xmlns:mc=compatibility/
mc:Ignorable=d d:DesignWidth= d:DesignHeight=>
<TextBlock x:Name=ShowTextBlock Text=Hello World FontSize=/>
</phone:PhoneApplicationPage>
namespace XamlSample
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
// Base
InitializeComponent()
}
}
}
Code范例
<phone:PhoneApplicationPage
x:Class=XamlSampleMainPage
xmlns=
xmlns:x=
xmlns:phone=clrnamespace:MicrosoftPhoneControls;assembly=MicrosoftPhone
xmlns:d=
xmlns:mc=compatibility/
mc:Ignorable=d d:DesignWidth= d:DesignHeight=>
</phone:PhoneApplicationPage>
namespace XamlSample
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
// Base
InitializeComponent()
// Create
TextBlock showTextBlock = new TextBlock()
showTextBlockName = ShowTextBlock;
showTextBlockText = Hello World;
showTextBlockFontSize = ;
thisContent = showTextBlock;
}
}
}
執行結果
這兩個WP的范例程序執行結果都是在畫面上顯示Hello World而我們在程序代碼裡加入斷點來檢視執行結果的對象(如下圖)可以看出兩個范例最終產生的對象結構是相同的也就是說不管是使用XAML或是使用程序代碼的方式來建構畫面對象都是相同的NET會依照開發人員設計的XAML內容建立對象就像是開發人員使用程序代碼建立對象一樣理解這個范例之後可以簡單的說XAML是用來產生對象的配置文件執行平台使用XAML產生的對象而NET依照設定來產生對象是采用Reflection我們也可以更廣義的說「XAML是用來產生對象的Reflection配置文件」
XAML范例中斷
Code范例中斷
本篇文章采用「XAML是用來產生對象的Reflection配置文件」這樣的角度剖析XAML來輔助開發人員理解XAML並且知道是如何透過XAML來產生對象
Object
Element
下面這段XAML
代表一個TextBlock對象
當程序執行的時候
NET會剖析XAML Element來產生一個TextBlock對象
像這樣會產生一個對象的XAML Element稱為「Object
Element」
<sample:TextBlock x:Name=
ShowTextBlock
Text=
Hello World
FontSize=
xmlns:sample=
clr
namespace:System
Windows
Controls;assembly=System
Windows
/>
有用過Reflection的開發人員
會知道組件名稱
命名空間
類別名稱
有這三項字符串數據就可以反射生成一個對象出來
在Object
Element裡
這三項數據也有各自設定的規范
依照XAML的規范來解讀上面這個Object Element
可以得到
「組件名稱」是System
Windows
「命名空間」是System
Windows
Controls
「類別名稱」則是TextBlockNET剖析Object Element之後
就會依照這些字符串數據
反射生成出一個TextBlock對象
將這個XAML Element取代Hello World范例裡的TextBlock依然可以正常的顯示Hello World
<phone:PhoneApplicationPage
x:Class=
XamlSample
MainPage
xmlns=
xmlns:x=
xmlns:phone=
clr
namespace:Microsoft
Phone
Controls;assembly=Microsoft
Phone
xmlns:d=
xmlns:mc=
compatibility/
mc:Ignorable=
d
d:DesignWidth=
d:DesignHeight=
>
<sample:TextBlock x:Name=
ShowTextBlock
Text=
Hello World
FontSize=
xmlns:sample=
clr
namespace:System
Windows
Controls;assembly=System
Windows
/>
</phone:PhoneApplicationPage>
當然這樣的XAML內容
看起來跟一般常見的XAML有所出入
一整個復雜了許多
因為XAML是由XML發展出來的
很多的格式沿用XML的規范
許多命名空間可以由上層的Element所提供
這樣的規范大量減少XAML需要設定的數據內容
這部分有興趣的開發人員可以參考XML的相關技術資料
另外各種開發平台也定義了一些默認的關鍵詞
讓XAML的設計可以變得更簡潔
這部分有興趣的開發人員可以參考開發平台的相關技術資料
以上面這個范例來說
因為是要產生開發平台預設的TextBlock
而這個開發平台預設的命名空間已經在PhoneApplicationPage做過宣告
所以可以將組件名稱
命名空間都省略掉
XAML經過這些規范的簡化之後
就可以產生出一般常見的XAML數據內容
Property
Attribute
下面這段XAML
代表一個TextBlock對象
TextBlock對象有一個Text屬性
當程序執行的時候
NET會剖析XAML Element來產生一個TextBlock對象
並且將這個TextBlock對象的Text屬性設定為Hello World
FontSize屬性設定為
像這樣會設定一個對象屬性的設定
稱為「Property
Attribute」
<TextBlock x:Name=
ShowTextBlock
Text=
Hello World
FontSize=
/>
查詢MSDN可以發現TextBlock的FontSize屬性
是一個型別為System
Double的屬性
而XAML因為是XML的格式
所以被限制了只能輸入字符串形式的數據
受於這樣的限制
NET剖析Property
Attribute的時候
會嘗試將字符串數據轉型為對象屬性的型別
以下面這個范例來說
在執行的階段會看到
NET的錯誤通知
告知無法將字符串數據轉型為System
Double
<TextBlock x:Name=
ShowTextBlock
Text=
Hello World
FontSize=
Clark
/>
Property
Element
在XAML的規范裡
Property
Attribute章節裡的TextBlock范例
也可以寫成下面范例的格式
將TextBlock的FontSize屬性改寫成為一對獨立的標簽
並且設定值寫在標簽的內容裡
像這樣設定一個對象屬性的設定
稱為「Property
Element」
<TextBlock x:Name=
ShowTextBlock
Text=
Hello World
>
<TextBlock
FontSize>
</TextBlock
FontSize>
</TextBlock>
PropertyElement的寫法看起來有點多余但其實這是為了XAML的延展性而設計一般對象的屬性有些不單純是intdouble這些實值型別也有可能是一個對象(Class)一個結構(Struct)而一個對象又會有屬性整個對象就是以樹狀結構生長下去這時PropertyAttribute使用字符串來設定這個對象樹狀結構會顯得力不從心PropertyElement定義了可以使用ObjectElement來當作內容來解決這個問題NET在剖析PropertyElement的時候會將ObjectElement內容反射生成出對應的對象設定為對象的對象屬性而使用ObjectElement來當作PropertyElement的內容另一個原因是ObjectElement自己是描述一個對象它又可以擁有自己的PropertyAttributePropertyElement這樣就可以一層一層設計出對象的樹狀結構
下面這段XAML采用PropertyElement來設定TextBlock對象的Foreground屬性而TextBlock對象的Foreground屬性是一個型別為Brush的對象屬性所以在PropertyElement裡采用ObjectElement來生成要設定給Foreground屬性的一個Brush對象
<TextBlock x:Name=ShowTextBlock Text=Hello World FontSize=>
<TextBlockForeground>
<SolidColorBrush Color=#FF />
</TextBlockForeground>
</TextBlock>
仔細看上面的范例會發現並不是生成一個Brush對象而是生成Brush的延伸對象SolidColorBrush這是因為Brush對象是一個抽象類並沒有辦法直接生成所以只能生成延伸自Brush的SolidColorBrush來當作Foreground屬性的對象這也就是說我們可以生成延伸類別來設定對象屬性這是一個面向對象開發很重要的功能提供了開發人員抽換對象的能力大幅增加系統對象的彈性
Property
Element
Collection
既然一般對象的屬性不單純是int
double這些實值型別
有可能是一個對象(Class)
一個結構(Struct)
就免不了的對象的屬性
也有可能是對象
結構的集合(Collection)
Property
Element另外也定義了
可以使用多個Object
Element來當作內容來解決這個問題NET在剖析Property
Element的時候
會將多個Object
Element內容反射生成出對應的對象
並且加入對象的對象集合屬性
下面這段XAML
采用Property
Element來設定LinearGradientBrush對象的GradientStops屬性
而LinearGradientBrush對象的GradientStops屬性
是一個GradientStop型別的對象集合屬性
所以在Property
Element裡采用多個Object
Element
來生成要設定給GradientStops屬性的多個GradientStop對象
<TextBlock x:Name=
ShowTextBlock
Text=
Hello World
FontSize=
>
<TextBlock
Foreground>
<LinearGradientBrush StartPoint=
EndPoint=
>
<LinearGradientBrush
GradientStops>
<GradientStop Color=
#FF
Offset=
/>
<GradientStop Color=
#
FF
Offset=
/>
<GradientStop Color=
#
FF
Offset=
/>
</LinearGradientBrush
GradientStops>
</LinearGradientBrush>
</TextBlock
Foreground>
</TextBlock>
後記
了解XAML的對象生成在學習WPFSilverlightWP等等開發平台的時候就可以參考MSDN類別庫資料來查詢透過XAML生成的對象了解對象本身的職責及工作內容以及設定每個屬性會讓對象發生何種變化這樣從對象本身開始學習的路線會比較正確而且快速並且不會被過多繁雜的變化所迷惑
From:http://tw.wingwit.com/Article/program/net/201311/13682.html