1. 程式人生 > >[No000013F]WPF學習之X名稱空間詳解

[No000013F]WPF學習之X名稱空間詳解

4.2 情況 之前 集中 sharp 要求 mes ble 實例

原文:[No000013F]WPF學習之X名稱空間詳解

X名稱空間裏面的成員(如X:Name,X:Class)都是寫給XAML編譯器看的、用來引導XAML代碼將XAML代碼編譯為CLR代碼。

4.1X名稱空間裏面到底都有些什麽?

x名稱空間映射的是:http://schemas.microsoft.com/winfx/2006/xaml,望文生義,它包含的類均與解析XAML語言相關,所以亦稱之為“XAML名稱空間”。

與C#語言一樣,XAML也有自己的編譯器。XAML語言被解析並編譯,最終形成微軟中間語言保存在程序集中。在解析和編譯XAML的過程中,我們經常要告訴編譯器一些重要的信息,如XAML編譯的結果應該和哪個C#代碼編譯的結果合並、使用XAML聲明的元素是public還是private訪問級別等等。這些讓程序員能夠與XAML編譯器溝通的工具就存在X:名稱空間中。

技術分享圖片技術分享圖片

我們註意到,它分為Attribute、標簽擴展、XAML指令元素三個種類。下面我們講講它們的具體用法:

4.2 X名稱空間中的Attribute

前面我們已經講過,Attribute和Property是兩個層面上的東西,Attribute是語言層面上的東西,是給編譯器看的,Property是面向對象層面上的東西,是給編程邏輯看。而且一個標簽中的Attribute大部分對應對象的Property。在使用XAML編程的時候,如果你想給它加一點特殊的標記來改變XAML對它的解析,這時候就需要額外的給它添加一些Attribute了。比如,你想告訴XAML編譯器將哪個編譯結果和那個C#編譯的類合並,這時候就必須為這個標簽添加X:Class Attribute來告訴編譯器。X:Class並不是對象成員,而是重X空間硬貼上去的。讓我們瀏覽一下常用的Attribute。

4.2.1 x:Class

這個Attribute是告訴XAML編譯器將XAML編譯器編譯的結果和後臺編譯結果的哪一個類進行合並,使用x:Class有以下幾點要求:

  • 這個Attribute只能用於根節點。
  • 使用x:Class的根節點的類型要與x:Class的值所指示的一致。
  • x:Class的值所指示的類型在聲明的時候必須使用partial關鍵字。
  • x:Class已經在剖析最簡單的XAML的時候已經講過,在這就不多講了。

4.2.2 X:ClassModiffier

這段代碼是告訴XAML編譯器有標簽編譯成的類具有什麽樣的訪問級別。

使用這個Attribute的時候需要註意的是:

  • 標簽必須具有x:Class Attribute。
  • X:ClassModiffier的值必須與X:Class所指定類的訪問權限一致。
  • X:ClassModiffier的值隨後臺代碼編譯語言的不同而有所不同。
4.2.3 X:Name 我們之前已經提過XAML是一種聲明式語言,但你是否想過XAML標簽聲明的是什麽呢?其實,XAML標簽聲明的是對象,一個XAML對應著一個對象,這個對象一般是一個控件類的實例。在.NET平臺上,類是引用類型。引用類型的實例一般都是以“引用者---實例”的形式成對出現的,而且我們只能通過引用者來訪問實例。當一個實例不在被任何引用者引用的時候,它將作為內存垃圾被銷毀。 常見的引用者是引用變量,但不是唯一的。比如下面這段XAML代碼:
  1. <Window x:Class="WpfApplication2.Window5"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="Window5" Height="300" Width="300">
  5. <Grid>
  6. <StackPanel Height="218" HorizontalAlignment="Left" Margin="19,31,0,0" VerticalAlignment="Top" Width="237">
  7. <TextBox Height="23" Width="120" />
  8. <Button Content="Button" Height="23" Width="75" />
  9. </StackPanel>
  10. </Grid>
  11. </Window>
這篇代碼中通篇沒有出現一次名字,但是我們可以通過引用者的層級關系來找到我們最終想要的控件,我們在Button的Click下寫如下代碼:
  1. private void Button_Click(object sender, RoutedEventArgs e)
  2. {
  3. StackPanel panel = this.Content as StackPanel;
  4. TextBox textBox = panel.Children[0] as TextBox;
  5. if (!string.IsNullOrEmpty(textBox.Name))
  6. {
  7. textBox.Text = textBox.Text;
  8. }
  9. else
  10. {
  11. textBox.Text = "NULL";
  12. }
  13. }
this.Content引用著StackPanel的實例,StackPanel.Children[0]又引用著TextBox的實例。知道了這個關系,就可以一路順著查找下來並同時進行類型轉換,最終TextBox中顯示的值是NULL。 理論上我們可以用上面的方法訪問到UI上的所有元素,但這畢竟太麻煩了。換句話說:XAML這種對象聲明語言只負責聲明對象而不負責為這些對象聲明引用變量。如果我們需要為對象準備一個引用變量以便在C#中直接訪問就必須顯示的告訴XAML編譯器-----為這個對象聲明引用變量,這時候,X:Name就派上用場了。 註意: X:Name的作用有兩個: (1)告訴編譯器,當一個標簽帶有x:Name時,除了為這個標 這個還真不能確定!簽生成實例還要給這個標簽聲明一個引用變量,變量名就是x:Name的值。 (2)將XAML標簽所對應的Name屬性(如果有)也設置為x:Name值,並把這個值註冊到UI樹上,以方便查找。 4.2.4 x:FieldModifier 使用了x:Name後,XAML標簽對應的實例就具有了自己的引用變量,而且這些引用變量都是類的字段,既然這樣就不免要關註一下它的訪問級別。默認情況下這些字段的級別都被設置成了Internal。在編程的時候,有的時候需要用一個程序集裏的一個窗體元素訪問到另一個程序集的窗體元素,那麽就需要使用x:FieldModifier來改變變量的訪問級別!
  1. <StackPanel Height="218" HorizontalAlignment="Left" Margin="19,31,0,0" VerticalAlignment="Top" Width="237">
  2. <TextBox Height="23" Width="120" x:Name="txtName" x:FieldModifier="internal"/>
  3. <Button Content="Button" Height="23" Width="75" Click="Button_Click" x:Name="btntest" x:FieldModifier="public"/>
  4. </StackPanel>
因為x:FidleModifier是應用變量的訪問級別,所以要配合x:Name一起使用。否則沒有引用變量,何來引用變量訪問級別。 4.2.5 x:Key 最自然的檢索方式莫過於”key-value“的形式了。在XAML文件中,我們可以把需要多次使用的類容提取出來放在資源字典中,需要使用的時候就用這個資源的key將這個資源檢索出來。 x:key的作用就是使用為資源貼上用於檢索的索引。在WPF中,幾乎每個元素都有自己的Resource屬性,這個屬性就是“key-value”的集合。只要把元素放進這個集合裏,這個元素就成了資源字典中的一個條目。當然,為了能檢索到這個條件,就必須為它添加x:Key。資源在WPF中非常重要,需要重復使用的XAML內容,如Style,各種Template和動畫都需要放在資源裏。 先讓我們看XAML代碼:
  1. <Window x:Class="WpfApplication2.Window4"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:sys="clr-namespace:System;assembly=mscorlib"
  5. xmlns:local="clr-namespace:WpfApplication2"
  6. Title="Window4" Height="369" Width="675">
  7. <Window.Resources>
  8. <local:Human x:Key="human" Child="ABC"></local:Human>
  9. <sys:String x:Key="myString">測試</sys:String>
  10. <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
  11. <Setter Property="Width" Value="30"></Setter>
  12. <Setter Property="Background" Value="black"></Setter>
  13. </Style>
  14. </Window.Resources>
  15. <Grid>
  16. <Label Content="{ StaticResource ResourceKey=myString}" Height="28" HorizontalAlignment="Left" Margin="177,81,0,0" Name="label1" VerticalAlignment="Top" />
  17. </Grid>
  18. </Window>
資源不但可以在XAML中使用,也可以在C#中訪問,C#中使用如下方式:
  1. string str = this.FindResource("myString") as string;
  2. this.label1.Content = str;
4.2.6 x:Shared 學習x:key的時候我們已經了解到,如果把某個對象作為資源放入資源字典裏後我們就可以把它們檢索起來重復使用。那麽每當我們檢索到一個對象,我們得到的究竟是同一個對象呢,還是這個對像的一個副本呢?這就要看我們為x:Shared賦什麽值了。x:Shared一定要與x:Key配合使用,如果x:Shared值為true,那麽每次檢索這個對象的時候,我們得到的都是同一個對象,反之,我們得到的就是這個對象的一個副本。默認這個值是true。也就是說我們使用的都是同一個對象。 4.3 x名稱空間下的擴展標簽 標記擴展實際就是一些MarkupExtension類的直接或間接派生類。x名稱空間中就包含一些這樣的類,所以稱其為x名稱空間標簽的標記擴展。 4.3.1 x:Type 顧名思義,x:Type應該是一個數據類型的名稱。一般情況下,我們在編程中操作的數據類型實例或者實例的引用。但有的時候我們也需要用到數據類型本身。 能讓程序員在編程的層面上自由的操作這些數據類型,比如在不知道具體類型的情況下創建這個類型的實例並嘗試調用它的方法,.NET命名空間裏還包含了名為Type的類做為所有數據類型在編程層面上的抽象。 當我們想在XAML中表達某一數據類型就需要用到x:Type標記擴展。比如某個類的一個屬性,它的值要求的是一個數據類型,當我們在XAML中為這個屬性賦值是就需要用到x:Type。請看下面這個例子:
  1. <UserControl x:Class="WpfApplication2.UserControl1"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6. mc:Ignorable="d"
  7. d:DesignHeight="52" d:DesignWidth="128">
  8. <Grid>
  9. <Button Content="Button" Height="30" HorizontalAlignment="Left" Margin="10,10,0,0" Name="button1" VerticalAlignment="Top" Width="106" Click="button1_Click" />
  10. </Grid>
  11. </UserControl>

  1. /// <summary>
  2. /// UserControl1.xaml 的交互邏輯
  3. /// </summary>
  4. public partial class UserControl1 : UserControl
  5. {
  6. public UserControl1()
  7. {
  8. InitializeComponent();
  9. }
  10. public Type MyWindowType { get; set; }
  11. private void button1_Click(object sender, RoutedEventArgs e)
  12. {
  13. Window myWin = Activator.CreateInstance(this.MyWindowType) as Window;
  14. if(myWin!=)
  15. {
  16. myWin.Show();
  17. }
  18. }
  19. }

  1. <Window x:Class="WpfApplication2.Window4"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:sys="clr-namespace:System;assembly=mscorlib"
  5. xmlns:local="clr-namespace:WpfApplication2"
  6. Title="Window4" Height="369" Width="675">
  7. <Window.Resources>
  8. <local:Human x:Key="human" Child="ABC"></local:Human>
  9. <sys:String x:Key="myString">測試</sys:String>
  10. <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
  11. <Setter Property="Width" Value="30"></Setter>
  12. <Setter Property="Background" Value="black"></Setter>
  13. </Style>
  14. </Window.Resources>
  15. <Grid>
  16. <local:UserControl1 HorizontalAlignment="Left" Margin="292,244,0,0" x:Name="userControl11" VerticalAlignment="Top" MyWindowType="{x:Type TypeName=local:Window1}"/>
  17. </Grid>
  18. </Window>
回顧一下之前的標記擴展語法,因為TypeExtension類的構造器可以接受數據類型名做為參數,所以我們完全可以這樣寫:
  1. UserWindowType="{x:Type local:Window1}"
編譯並運行程序,單擊主窗體上的按鈕,自定義窗口就會顯示出來,我們還可以多寫幾個窗體來擴展這個程序,到時後只需要修改MyWindowType裏面的值就可以了。 4.3.2 x:Null 在XAML裏面表示空值就是x:Null。 大部分時間我們不需要為屬性附一個Null值,但如果一個屬性就有默認值而我們有不需要這個默認值就需要用的null值了。在WPF中,Style是按照一個特定的審美規格設置控件的各個屬性,程序員可以為控件逐個設置style,也可以指定一個style目標控件類型,一旦指定了目標類型,所有的這類控件都將使用這個style----除非你顯示的將某個實例的Style設置為null。 請看下面的事例:
  1. <Window x:Class="WpfApplication2.Window4"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:sys="clr-namespace:System;assembly=mscorlib"
  5. xmlns:local="clr-namespace:WpfApplication2"
  6. Title="Window4" Height="369" Width="675">
  7. <Window.Resources>
  8. <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
  9. <Setter Property="Width" Value="30"></Setter>
  10. <Setter Property="Background" Value="black"></Setter>
  11. </Style>
  12. </Window.Resources>
  13. <Grid>
  14. <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="180,256,0,0" Name="button1" VerticalAlignment="Top" Click="button1_Click" />
  15. <Label Content="{ StaticResource ResourceKey=myString}" Height="28" HorizontalAlignment="Left" Margin="177,81,0,0" Name="label1" VerticalAlignment="Top" />
  16. <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="button2" VerticalAlignment="Top" />
  17. <Button Content="{x:Static local:Window4.Test}" Height="23" HorizontalAlignment="Left" Margin="128,12,0,0" Name="button3" VerticalAlignment="Top" Style="{x:Null}"/>
  18. </Grid>
  19. </Window>
當然了,x:null也可以使用屬性標簽來設置這個值,前面已經講過,在這就不在講了。 4.3.3 x:Array 通過它的item屬性向使用者暴露一個類型已知的ArrayList實例,ArrayList內成員的類型由x:Array的Type指明。下面這個例子就是把ArrayList做為數據源向一個ListBox提供數據:
  1. <Window x:Class="WpfApplication2.Window4"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:sys="clr-namespace:System;assembly=mscorlib"
  5. xmlns:local="clr-namespace:WpfApplication2"
  6. Title="Window4" Height="369" Width="675">
  7. <Grid>
  8. <ListBox Height="100" HorizontalAlignment="Left" Margin="435,110,0,0" Name="listBox1" VerticalAlignment="Top" Width="176">
  9. <ListBox.ItemsSource>
  10. <x:Array Type="sys:String">
  11. <sys:String>Jim</sys:String>
  12. <sys:String>Darren</sys:String>
  13. <sys:String>Frank</sys:String>
  14. </x:Array>
  15. </ListBox.ItemsSource>
  16. </ListBox>
  17. </Grid>
  18. </Window>
4.3.4 x:Static 這是一個很常用的標記擴展,它的作用是在XAML文檔中使用數據類型為static的成員。因為XAML不能編寫邏輯代碼。所以使用x:Static訪問的static成員一定是數據類型的屬性和字段。我們看如下一些例子:
  1. public Window4()
  2. {
  3. InitializeComponent();
  4. //SolidColorBrush brush = new SolidColorBrush();
  5. //brush.Color = Colors.Blue;
  6. //this.rectangle1.Fill = brush;
  7. }
  8. public static string Test = "明月松間照,清泉石上流。";
  1. <Window x:Class="WpfApplication2.Window4"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:sys="clr-namespace:System;assembly=mscorlib"
  5. xmlns:local="clr-namespace:WpfApplication2"
  6. Title="Window4" Height="369" Width="675">
  7. <Grid>
  8. <Button Content="{x:Static local:Window4.Test}" Height="23" HorizontalAlignment="Left" Margin="128,12,0,0" Name="button3" VerticalAlignment="Top" Style="{x:Null}"/>
  9. </Grid>
  10. </Window>
如果一個程序需要支持國際化,一般需要把顯示的字符串保存在一個資源類的Static屬性中,所以支持國際化的程序UI中對x:Static的使用相當的頻繁。 4.4 XAML指令元素
XAML指令元素只有兩個:
  • x:Code
  • x:XData
我們之前已經在代碼後置一節介紹過x:Code標簽,它的作用是可以在XAML文檔中可以編寫後置的C#後臺邏輯代碼,這樣做的好處就是不需要把XAML和C#分放在兩個文檔當中,這樣寫的問題是代碼不容易維護,不宜調試,一般沒有人願意這麽幹。 x:XData是一個專用標簽。WPF把包含數據的對象稱為數據源,用於把數據源中的數據提供給數據使用者的對象被稱做是數據提供者,WPF中包含多種數據提供者,其中一個類名叫做XmlDataProvider實例,那麽XmlDataProvider實例的數據就要放在x:XData的標簽內容裏。事例如下: 技術分享圖片

[No000013F]WPF學習之X名稱空間詳解