卷首語:根據第一篇的知識,我們知道WPF應用是由控制台程序創建的,擁有自己獨立的消息循環。所以在之后的文章里和示例里,我會默認的選擇開啟控制台顯示,以方便調試以及輸出一些信息。並且為了簡便,推薦直接創建WPF項目,因為畢竟沒有人真會無聊到拿控制台去管理一個WPF應用的生命周期,也沒人會New一個又一個的Window對象和Controls。因為WPF有自己的UI展現形式——XAML。
言歸正傳:
我們先來弄明白XAML的定義
XAML是一種相對簡單的、通用的聲明式語言,它適合於創建和初始化.NET對象,XAML本身並不具備有意義的元素,它僅僅是提供一些關鍵字及規則,來告知編譯器和解析器如何處理XML。
從它的定義中,我們可以看到XAML是一種聲明式語言,擁有通用性。並且它的作用受到了限制,僅僅適合用於創建和初始化.Net對象。這兩個特性告訴我們什么呢?就是XAML語言可以被應用在.NET平台下的其它語言或者其它技術中,如WF。
那么XAML與WPF是什么關系呢?
XAML是通用的 那么它就不應該受到框架的限制,因此它與WPF是相互獨立的,比如可以使用單獨的XAML語言來創建窗體、控件等。然而XAML並不是萬能的,就如同XML一樣,也同樣需要解析。我們在實現一個WPF應用時,可以選擇是否使用XAML,因為XAML的作用是創建和初始化.NET對象,每一件XAML可以做到的事情,任何一門.NET語言都可以做到,然而反過來則不行。舉個不恰當的例子……巴基斯坦和卡巴斯基有神馬關系?回答:基巴關系。 嗯是的,確實只有基巴關系,卡巴斯基是通用的,但是也得有人用,巴基斯坦人民可以選擇是否使用卡巴斯基來簡化殺毒這件事情的工作……
以上說了一堆廢話,也比較難以理解,還請大家見諒,因為看WPF揭秘的時候這里就很難理解。反復看了很多遍,一直很糾結,撓牆的心都有了。其實這里只是想大家能有一個基本的認識,XAML != WPF。XAML雖然是針對WPF設計的,但XAML的應用並不限制於WPF,只要有合適的解析方式,XAML可以適用於任何語言和技術的展現。另外補一句……打算看書自學的……先看WPF設計指南吧……揭秘這本書……太高深了……
下面我們來看一段簡單的XAML,也是WPF模版生成的Window窗體的XAML
<Window x:Class="WPF_Xaml_Study.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> </Grid> </Window>
這段Xaml 如果了解XML的朋友看起來並不困難,從XML的視角來看它擁有
一個Window 類型的根元素和一個Grid類型的子元素
Window根元素命名空間為 http://schemas.microsoft.com/winfx/2006/xaml/presentation
自定義x命名空間http://schemas.microsoft.com/winfx/2006/xaml
Title Height Width 是Window元素的 Attribute 稱為特性
以XML的世界觀看完了這段XAML,我們再來以XAML的世界觀來看
x:Class 的作用是為根元素定義一個派生自元素類型的類 也就是標記了這個Window實例化的不是原始的Window 而是WPF_Xaml_Study.MainWindow
Window的命名空間包括了System.Windows命名空間下的絕大部分命名空間及類型。
x命名空間包括了擴展標記類型
Title Height Width 對應了Window類型的對應屬性 因此也稱為 Property Attribute 屬性特性
下面我以一個簡單的Button控件的例子 來一一對應XAML與CLR中相應類型的關系
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK"></Button>
Button 實際是由System.Windows.Controls提供的 它在CLR中對應的狀態應該是怎樣的呢?
//等同於Xaml中聲明的Button Button button = new Button();
button.Content = "OK";
它聲明了一個Button對象,並且將其Content屬性設置為了 "OK"
XAML中,元素 Attribute的定義有兩種 一種是對應的CLR中的類型屬性,另一種 是對應的CLR中的類型的事件
其實XAML應用起來 還是比較簡單的
下面我們來看XAML的神奇亮點之一 ( 命名空間 )
在XML中,也有命名空間的概念,XML的命名空間往往就是一段唯一的URL 如:http://schemas.Microsoft.com
而在XAML中,命名空間有兩種聲明方式。
第一種很傳統,還是用的URL方式
http://schemas.microsoft.com/winfx/2006/xaml/presentation
第二種更傳統,使用的是CLR 程序集、命名空間的方式
xmlns="clr-namespace:System.Windows;assembly=PresentationCore"
xmlns="clr-namespace:System.Windows;assembly=PresentationFramework"
在剛剛的Button例子中 這兩種方式的效果是等價的。
這是為什么呢?
答案很簡單 http://schemas.microsoft.com/winfx/2006/xaml/presentation這個看似簡單的命名空間,包含了N多的System.Windows下的各個子命名空間的中的類型。比如Button就被定義在PresentationFramework這個程序集的Controls命名空間下
下圖羅列了這個命名空間所包含的CLR命名空間
這么一個XML命名空間引入了這么多的CLR命名空間很神奇是不是?這要用using 不定要引入到猴年馬月呢。
其實這個命名空間,是通過在程序集中進行了硬編碼,將CLR的命名空間映射為了XML的命名空間。
我們可以設置自己的XML命名空間與CLR命名空間的映射。
在AssemblyInfo中 ,使用XmlnsDefinitionAttribute 添加CLR命名空間對應XML命名空間的映射
XmlnsDefinitionAttribute 位於System.Windows.Markup命名空間下
[assembly: XmlnsDefinition("http://Manon.Loki.Com","WPF_Xaml_Study")]
由於XML命名空間與CLR命名空間是1對多的的關系,所以要注意其中的類型是否存在二義性
XAML 亮點之二 (屬性元素)
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK"></Button> <Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" > <Button.Content> OK </Button.Content> </Button>
通過對比兩個Button, 我們可以發現設置Button的Content擁有兩種方式。
第一種 通過Attribute進行設置
第二種 通過子元素進行設置,時候Content元素就被稱為屬性元素,而Button則為對象元素,中間使用.進行分隔符
<ObjectElement.PropertyElement> 這種通用的寫法。
WPF提供了屬性元素有什么好處呢?
一個類型的屬性不一定是簡單類型,如果是復雜類型的話, Attribute就無法進行正確的表達,這時候可以以屬性元素的方式,進行精確的表達。
例如:我想讓Button的Content是一個圖形,而非普通的文字,只需要在Content屬性下創建符合該類型值的子類就好。
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <Button.Content> <Rectangle Width="50" Height="50" Fill="Red"></Rectangle> <Button.Content> </Button>
XAML亮點之三 (擴展標記)
這個要說的不多,大家知道其大概意思及原理即可。
WPF提供了幾個擴展標記 位於System.Windows.Markup命名空間下
其對應的XML命名空間http://schemas.microsoft.com/winfx/2006/xaml
系統提供了很多擴展標記 如:Static Null Binding等。
那么擴展標記是如何工作的呢?
下邊寫一個簡單的例子
<Button Content="使用擴展標記設置Background" Background="{x:Null}" Height="{x:Static Member=SystemParameters.IconHeight}"></Button>
Background與Height都使用了擴展標記。
其中Height的 x:Static Background的x:null為標記擴展類型。
Member為命名參數
最后的字符串SystemParameters.IconHeight 被稱為定位參數
我們要注意擴展標記僅適用於 Attribute 在使用的時候 通過"{}" 括起來 表示這是一個擴展標記而非一個普通的字符串。
"{}"中的字符串會根據標記擴展類型去查找對應的處理類,並且根據定位參數來獲取值
由於存在標記擴展的因素,所以我們在賦予XAML 帶有{}的字符串類型的值得時候,要避免被系統認為是標記擴展
以下為兩種解決方式
<!--方式1 使用一個{}表示擴展標記,而后跟隨聲明的值--> <Button Content="{}{這是一個帶花括號的Button}"></Button> <!--方式2 使用屬性元素,因為只有在Attribute中 花括號才會被認為是擴展標記--> <Button> <Button.Content> {同樣是一個帶花括號的Button} </Button.Content> </Button>
XAML亮點之四 (內容屬性)
內容屬性其實很簡單,就是每個控件都有一個默認的屬性,當對這個控件類型的內容賦值時,會自動把值賦給指定的屬性。
例如Button的Content就是它的內容屬性。因此通過XAML對Button的Content賦值的時候可以有一種簡寫的寫法。
<Button>It's a Button</Button>
其它的的控件 例如ListBox的Items為內容屬性。一個控件內容屬性的確定大體上是根據控件的類型來決定的
以上為XAML與XML不同的地方。
下面是額外的一些知識 了解即可,因為這是編譯器幫我們做的。
我們在項目中創建了MainWindow.xaml與MainWindow.xaml.cs
當我們編譯整個項目的時候
MainWindow.xaml會被編譯為MainWindow.Baml
MainWindow.xaml.cs會被編譯喂MainWindow.g.cs
BAML(Binary Application MarkUp Language)的縮寫,這是一種被解析之后生成的二進制文件,它會作為默認的二進制資源嵌入到程序集中。因此不用糾結大批量的XAML文檔處理問題。
MainWindow.g.cs為系統生成的類型 會被編入程序集 對應MainWindow.xaml.cs
Tips:這一篇就這么多了。看書啃得很累,寫出來也發現很累,希望大家以辨證的眼光來看待這篇文章,因為那本WPF揭秘實在是太深奧了。還是那句老話,也許我理解會有偏差 希望大家看到了 能及時提醒我 謝謝