《Inside XAML》翻译半成品
時間倉促,胡亂翻譯了一通,并沒有完全按照原文去翻譯,我是照我的理解來的。不明白只處請參照原文。
什么是XAML?
XAML的全稱是eXtensible Application Markup Language,用于像HTML構建WEB頁面一樣構建應用程序的界面——當然,同樣也可以構建WEB頁面,只要使用不同的編譯器就可以。Longhorn的系統界面就是使用XAML構建的。
XAML的"Hello World"
<FlowPanel?xmlns="http://schemas.microsoft.com/2003/xaml">
????<Text>Hello?World</Text>
????<Button>Click?me!</Button>
</FlowPanel>
以上代碼表示在頁面上以“流”的方式顯示一段文本和一個按鈕。其效果如下圖:
為什么需要一種新的標記語言呢?
?????? 微軟設計了這種新的標記語言,而沒有使用原有的HTML或SVG(Scalable Vector Graphics -- 一種基于XML的強大的圖形系統)。其主要原因是:
1、HTML主要是用于WEB上的,而XAML則可以用到應用程序上。
2、XAML與運行時(runtime)有者很大的關聯,而SVG則沒有。XAML是被設計來直接集成在WinFX上的。
XAML與對象
??? 每一個XAML中的元素在運行時里都對應一種對象,拿上面的例子來說,程序在運行的時候就對應三種對象:FlowPanel, Text, 和 Button。這些對象都是Avalon類庫種的一部分——XML命名空間http://schemas.microsoft.com/2003/xaml 已經告訴了我們類的來源。當然,你也可以自己定義自己的類。甚至可以用XAML寫出控制臺應用程序。
??? 通常,運行時對XAML文件的處理時編譯而不是解析。當你編譯一個基于XAML的項目的時候,編譯器會為每一個XAML文件生成一個類,那些類包含了一些代碼,用來生成在XAML文件中指定的對象。如果希望看到XAML生成的代碼,可以使用Longhorn下的Visual Studio .NET Whidbey(具體過程不在此闡述,請查看原文)。
??? 打開生成的代碼文件,可以看到一個類的定義。對于每一個XAML文件來說,編譯器將只會生成一個類,而且此類將繼承自XAML根元素所描述的類。例如,對于上面所說的那個XAML文件,它的根元素是FlowPanel,生成的代碼就是:
{
//?創建主面板
MSAvalon.Windows.Controls.FlowPanel?_FlowPanel_1_?=?this;
((MSAvalon.Windows.Serialization.ILoaded)(_FlowPanel_1_))
????.DeferLoad();
//?創建Text
MSAvalon.Windows.Controls.Text?_Text_2_?=?
????new?MSAvalon.Windows.Controls.Text();
((MSAvalon.Windows.Serialization.ILoaded)(_Text_2_))
????.DeferLoad();
//?把Text設置為FlowPanel的子結點
((MSAvalon.Windows.Serialization.IAddChild)(_FlowPanel_1_))
????.AddChild(_Text_2_);
((MSAvalon.Windows.Serialization.IAddChild)(_Text_2_))
????.AddText("Hello?World");
((MSAvalon.Windows.Serialization.ILoaded)(_Text_2_))
????.EndDeferLoad();
//?創建Button
MSAvalon.Windows.Controls.Button?_Button_3_?=?
????new?MSAvalon.Windows.Controls.Button();
((MSAvalon.Windows.Serialization.ILoaded)(_Button_3_))
????.DeferLoad();
((MSAvalon.Windows.Serialization.IAddChild)(_FlowPanel_1_))
????.AddChild(_Button_3_);
((MSAvalon.Windows.Serialization.IAddChild)(_Button_3_))
????.AddText("Click?me!");
((MSAvalon.Windows.Serialization.ILoaded)(_Button_3_))
????.EndDeferLoad();
((MSAvalon.Windows.Serialization.ILoaded)(_FlowPanel_1_))
????.EndDeferLoad();
}
??? 所有代碼都是在編譯期被生成的,也就是說,在運行期XAML文件是用不著的。如果你想動態地生成用戶界面,沒有必要通過編譯XAML來實現,你可以使用WinFX提供的API來把未被編譯的XAML直接轉換成對象。
屬性
??? 就像創建對象一樣,XAML也允許為對象設置屬性。例如,我們可以這樣修改Button元素:
Button_3_.Background?=?
????new?MSAvalon.Windows.Media.SolidColorBrush(
??????MSAvalon.Windows.Media.Color.FromARGB(255,?255,?0,?0)
??????????????????????????????????????????????);
??? 如果想知道XAML編譯器是怎么把Red轉換成以上代碼的,你可以使用.Net一直在使用的技術:類型轉換。類型轉換是.Net設計時環境的一部分,它用來對顯示在VS.Net屬性窗口中的屬性值和對象屬性的實際屬性進行相互轉換。類型轉換也可以生成代碼來初始化對象的屬性——在Windows Forms應用程序中,VS.Net在InitializeComponent方法中使用他們來創建代碼。同樣,XAML編譯器使用類型轉換技術來把屬性字符串轉換成初始化代碼。
復雜屬性
??? 并不是所有屬性都可以使用字符串來表示,有些屬性是由一系列嵌套的對象組織起來的。XAML支持一種被叫做“復雜屬性”的特殊語法,使用它可以通過設置子元素——而不是屬性字符串——來設置對象的屬性,這個時候,XAML元素表示一個復雜屬性,而不是子對象。表示復雜屬性的元素必須有一定的規則:它必須是父元素所表示對象的一個屬性的名稱。例如:
??<Button.Background>
????<LinearGradientBrush>
??????<LinearGradientBrush.GradientStops>
????????<GradientStopCollection>
??????????<GradientStop?Color="Red"?Offset="0"?/>
??????????<GradientStop?Color="Magenta"?Offset="0.25"/>
??????????<GradientStop?Color="Blue"?Offset="0.5"/>
??????????<GradientStop?Color="White"?Offset="1"/>
????????</GradientStopCollection>
??????</LinearGradientBrush.GradientStops>
????</LinearGradientBrush>
??</Button.Background>
??Click?me!
</Button>
?????? 這個例子并不是想一般的類型轉換機制那樣把字符串轉換成一個“brush”,而實際上我們通過標記創建了一個“復雜的brush”——LinearGradientBrush ,同時,還創建了很多的填充區(fill stages)。這個例子創建了兩個復雜屬性,他們一個嵌套著一個。<Button.Background>元素設置了Button的背景屬性,在它的內部,<LinearGradientBrush.GradientStops>元素設置了“linear gradient brush”的GradientStops 屬性。復雜屬性的語法工作方式與其他的XAML元素一樣——它也允許構建對象樹,唯一不同的是,他們將會被指定為元素的屬性而不是子元素。顯示的結果是:
添加代碼
??? 如我們所知,XAML編譯器為每一個XAML文件生成一個派生自根元素類型的類,并且包含創建所有子元素的代碼。然而,只生成這些代碼還不足以構建一個UI,用戶界面不僅是要展示信息,也必須能夠響應用戶的輸入。因此,通常都要添加一些代碼來提供UI的行為。
??????? 把代碼寫進XAML文件是可以實現的。你可以通過Definition 命名空間中的<Code> 元素,把代碼直接寫在里面,XAML編譯器將會把它添加到生成的代碼中去。添加代碼時,應該把代碼寫到CDATA 段中去,例如:
????xmlns:def="Definition">
????<Text>Hello?World</Text>
????<Button>Click?me!</Button>
????<def:Code>
??????<![CDATA[
????????//?Will?be?added?to?generated?source?file
????????public?string?Hello()
????????{
??????????return?"Hello!";
????????}
??????]]>
????</def:Code>
</FlowPanel>
??????? 然而,做過動態WEB頁面的人都知道,把代碼和標記都放到一個文件中時極其不易維護的。最好就是把UI的描述和響應UI動作的代碼分割開來。使用一種與“code-behind”很像的技術就可以實現代碼和標記的分離——利用partial 關鍵字(partial關鍵字的介紹請參考C# 2.0規范)。于是,上面的代碼就可以寫成: public?partial?class?MyPanel
{
??public?string?Hello()
??{
????return?"Hello!";
??}
}
????? 當你用Visual Studio .NET創建一個XAML項目時,每個XAML文件會自動產生一個與之相對應的partial代碼文件,在這個文件中添加的代碼將會在編譯XAML的時候自動添加到XAML的代碼中。
?? 當你為一個XAML文件寫代碼的時候,你也希望可以對標記描述的對象進行操作,以便控制它。這時候,你需要給標記中描述的對象加上一個ID屬性:
<Text?ID="textElem">Hello?World</Text>
??? 完成上面的工作以后,XAML編譯器將會把對象的ID設置成上面所指定的ID。例如,上面的例子就可以這樣使用:
textElem.TextRange.Text?=?"Foo";
要寫的代碼并不經常是上面所說的那種,而是那些復雜的事件處理。
事件處理
添加代碼最主要的原因是進行事件處理,處理那些來自用戶,或是來自UI本身的事件。我們可以通過簡單的添加屬性字段來描述對象要處理的事件,例如,讓Button處理Click事件:
這將使編譯器生成這樣一段代碼:
_Button_4_.Click?+=?
????new?MSAvalon.Windows.Controls.ClickEventHandler(this.OnClick);
為了讓他通過編譯,我們必須在代碼文件中寫一個相應的OnClick方法,Button使用的delegate是ClickEventHandler ,所以,我們寫的方法應該有相應的簽名:
private?void?OnClick(object?sender,?ClickEventArgs?e)
{
????textElem.TextRange.Text?=?"Foo";
}
結論
XAML是一種簡單但很強大的構建.Net對象樹的方法。因為XAML基于XML,所以我們可以直接基于XAML來創建程序。這不僅僅使手工創建UI很容易,這也是與生成XAML的工具直接相關的——未來的設計工具也將能過使用XAML格式導出文檔或繪制界面,也將會使通過XSLT把XML數據轉換到XAML中變得容易。XAML使用戶界面設計清晰的從代碼中分離出來,而且,XAML被集成到WinFX中,這使得使用代碼操作那些定義在文件中的元素很容易。
總結
以上是生活随笔為你收集整理的《Inside XAML》翻译半成品的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 迷你世界多久更新汽车 24期迷你世界一
- 下一篇: 中国人民银行(中国纪录片网)