WPF程序的XAML代码中,在顶级元素中都能看到xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
来引入http://schemas.microsoft.com/winfx/2006/xaml
这个名称空间。
与C#语言一样,XAML也有自己的编译器。XAML语言会被解析并编译,最终形成微软中间语言存储在程序集中。在解析和编译XAML语言的过程中,我们经常需要告诉编译器一些重要的信息,比如XAML代码的编译结果应该与哪个C#代码的编译结果合并、使用XAML声明的元素是public
还是private
访问级别等等,这些让程序员能够与XAML编译器沟通的工具就存放在x
名称空间中。
常用的Attribute
Attribute
与Property
不同。Attribute
是语言层面上的东西,是给编译器看的,Property
是面向对象层面的东西、是给编程逻辑用的,而且一个XAML标签的Attribute
里大部分都对应着对象的Property
。
在使用XAML编程的时候,如果想加上一些特殊的标记从而影响XAML编译器对它的解析,这时候就需要额外为它添加一些Attribute
了。比如希望告诉XAML编译器将编译结果与哪个C#编译的类合并,就必须使用x:Class=”目标类名”
。
一、x:Class
x:Class
的作用是告诉XAML编译器将XAML标签的编译结果与后台代码中指定的类合并。
使用要求
- 只能用于根节点。
x:Class
所在的根节点的类型要与目标类型保持一致。x:Class
的目标类型在声明时必须使用partial
关键字。
<Window x:Class="DigitaPlatform.Views.MainWindow" ......> ...... </Window>
二、x:ClassModifier
x:ClassModifier
的作用是告诉XAML编译由标签编译生成的类具有什么样的访问控制级别。
使用要求
- 所在标签必须具有
x:Class
。 x:ClassModifier
的值必须与x:Class
的目标类的访问控制级别一致(默认为public
)。x:ClassModifier
的值随后台代码的编译语言不同而有所不同,可以参考TypeAttributes
枚举。
<Window x:Class="DigitaPlatform.Views.MainWindow" x:ClassModifier="internal" ......> ...... </Window>
三、x:Name
XAML是一种声明式语言,其声明的是对象。也就是说一个XAML标签会对应着一个对象,这个对象一般是一个控件类的实例。当我们希望去调用对应的实例时,可以根据XAML中空间的层级关系来找到对应的引用,但是这种方式如果XAML层级结构很复杂那么用起来就十分麻烦。因此,可以为标签对象准备一个引用变量以便在C#代码中直接访问,这时就需要使用x:Name
。
作用
- 告诉XAML编译器,除了为这个标签生成对应实例外还要为这个实例声明一个引用变量,变量名就是
x:Name
的值。 - 将XAML标签所对应对象的
Name
属性(如果有)也设为x:Name
的值,并把这个值注册到UI树上,以方便查找。
关于应该使用Name
还是x:Name
,Name
属性是定义在FrameworkElement
类中的,所有的WPF控件都具有Name
这个属性(继承FrameworkElement
),而当一个元素具有Name
属性时,使用Name
还是x:Name
效果是一样的。而对于那些没有Name
属性的元素,为了在XAML声明时也能创建引用变量以便在C#代码中访问,就只能使用x:Name
了。在使用过程中,可以全程x:Name
以增强代码的统一性和可读性。
<TextBlock x:Name="txt_Header"/>
四、x:FieldModifier
在使用x:Name
后,XAML标签对应的实例就具有了自己的引用变量,而且这些引用变量都是类的字段。默认情况下,这些字段的访问级别是internal
,如果希望从一个程序集访问另一个程序集窗体中的元素,就需要把被访问控件的引用变量改为public
级别,x:FieldModifier
就是用来在XAML里改变引用变量访问级别的。
使用要求
x:FieldModifier
所在的元素必须使用了x:Name
。
<TextBlock x:Name="txt_Header" x:FieldModifier="public"/>
五、x:Key
x:Key
的作用就是为资源贴上用于检索的索引。在WPF中,几乎每个元素都有自己的Resources
属性(也就是资源),是一个Key-Value
的集合,只要把元素放进到这个集合,这个元素就称为资源字典中的一个条目,为了能够检索到这个资源,就必须为它添加x:Key
。
XAML方式使用x:Key
<Window ......>
<Window.Resources>
<sys:String x:Key="stringTest">测试......</sys:String>
</Window.Resources>
<Grid>
<TextBlock Text="{StaticResource stringTest}"/>
</Grid>
</Window>
后台代码使用资源
C#代码中,在一个拥有Resources
属性的控件对象中使用FindResource
方法就可以在它的资源字典里获取资源。
var data = FindResource("stringTest").ToString();
六、x:Shared
默认情况下,我们通过x:Key
获取到一个对象时,都是同一个对象。除非通过x:Shared="false"
来将分享关闭,这样每次在通过x:Key
来获取对象时,得到的都是这个对象的一个新的副本。
使用要求
x:Shared
一定要与x:Key
配合使用。
常用的标记扩展
标记扩展实际上就是一些MarkupExtension
类的直接或间接派生类。x名称空间中就包含有一些这样的类,所以常称它们为x名称空间内的标记扩展。
一、x:Type
当我们在XAML中想表达某个数据类型时,就需要使用x:Type
标记扩展。比如某个类的一个属性,它的值要求是一种类的类型(Type
),那么当我们在XAML中为这个属性赋值时就要使用x:Type
。
示例
定义一个Button
子类
class MyButton:Button
{
public Type? StringType { get; set; }
}
在XAML中创建该类,并为StringType
属性赋值。
<Window ......
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp2"
xmlns:sys="clr-namespace:System;assembly=System.Runtime" ...... >
<Window.Resources>
<local:MyButton x:Key="myButton" stringType="{x:Type sys:String}"/>
</Window.Resources>
......
</Window>
DataContext
此外,这里多提一下,在XAML直接设置DataContext
时,可以在元素中为DataContext
属性赋值,如果是内联的写法,也是要使用x:Type
。(这里猜测内联方式应该是指定DataContext
的类型,有空再翻看源码)
内联写法
<Window ......
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp2"
DataContext="{x:Type local:MainWindowViewModel}" ......>
......
</Window>
标签写法
<Window ......
xmlns:local="clr-namespace:WpfApp2"
......>
<Window.DataContext>
<local:MyButton/>
</Window.DataContext>
</Window>
二、x:Null
有时需要显式的对一个属性赋一个空值,在C#中使用null
关键字来表示,而XAML中则使用x:Null
来表示。大多数情况下是不需要显式的为一个属性赋null
值的,但如果一个属性具有默认值而我们又不需要这个默认值的时候就需要显式的设置null
值了。
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Blue"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<Button Width="100" Height="50" Content="ButtonOne"/>
<Button Width="100" Height="50" Content="ButtonTwo" Style="{x:Null}"/>
</StackPanel>
</Grid>
三、x:Array
x:Array
的作用是通过它的Items
属性向使用者暴露一个类型已知的ArrayList
实例,ArrayList
内成员的类型由x:Array
的Type
属性指明。
<Window ......
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=System.Runtime" ......>
<Window.Resources>
<x:Array Type="sys:String" x:Key="data">
<sys:String>one</sys:String>
<sys:String>two</sys:String>
<sys:String>three</sys:String>
</x:Array>
</Window.Resources>
<Grid>
<ComboBox ItemsSource="{StaticResource data}"/>
</Grid>
</Window>