WPF之X名称空间详解
XAM简介:
XAML是一种专门用于绘制UI的语言,借助它就可以把UI定义与运行逻辑分离开来。XAML使用标签来定义UI元素,每个标签对应.NET Framework类库中的一个控件类。通过设置标签的Attribute
,不但可以对标签对应控件对象的Property
进行赋值,还可以做一些额外的事情(如声明名称空间,指定类名等)。
为对象属性赋值的语法有如下方法:(1)使用标签的Attribute(2)使用TypeConverter
类将XAML标签的Attribute
和Property
进行映射(3)属性元素,即某个标签的一个元素(其子级标签)对应这个标签的一个属性(4)标记扩展,大多数赋值都是为属性生成一个新对象,但有时候需要把同一个对象赋值给两个对象的属性,还有的时候需要给对象的属性赋一个null值,或者将一个对象的属性依赖于其他对象的某个属性上等,当需要为对象的属性进行这些特殊类型赋值时,就需要标记扩展。
X名称空间中的Attribute
x:Class
指示XAML编译器将XAML标签的编译结果与后台代码中指定的类合并,需遵循:
- 只能用于根节点
- 使用x:class根节点的类型要与x:Class的值所指示的类型保持一致
- x:Class的值指示的类型在声明时,必须使用
partial
关键字
x:ClassModifier
的值必须与x:Class
所指示的访问控制级别一致
x:Name
XMAL这种对象声明语言只负责声明对象而不负责 为这些对象引用变量,如果需要准备一个引用变量以便在C#代码中直接访问就必须显式地告诉XAML编译器,为这个对象声明引用变量,这就是x:Name
的作用,即:
- 告诉XAML编译器,当一个标签带有
x:Name
时除了为这个标签生成对应实例外还要为这个实例声明一个引用变量,变量名就是x:Name
的值。 - 将XAML标签对于对象的Name属性(如果有)也设为x:Name的值,并把这个值注册到UI树上,以方便查找。
对于没有Name
属性的元素,为了在XAML声明时也创建引用变量以便在C#代码中访问,就只能用x:Name
,建议全部使用x:Name
以增强代码的统一性和可读性。
x:FieldModifier
使用x:Name
后,XAML标签对应的实例就具有了自己的引用变量,而且这些引用变量都是类的字段。默认情况下,这些字段的访问级别按照面向对象的封装原则被设置为internal
。在编程的时候,有时候我们需要从一个程序集访问另一个程序集窗体的元素,这时候就需要把被访问空间的引用变量改为public
。
需要注意的是:因为x:FieldModifier是用来改变引用变量访问级别的,所以使用x:FieldModifier的前提是这个标签也同时使用x:Name
x:Key
在XAML文件中,我们可以把很多需要多次使用的内容提取出来放在资源字典中,需要使用的时候就用它的key检索出来。
<Window.Resources>
<sys:String x:Key="myString">Hello WPF</sys:String>
</Window.Resources>
<StackPanel Background="Gray">
<TextBox Text="{StaticResource ResourceKey=myString}" Margin="5"></TextBox>
<TextBox x:Name="textBox1" Margin="5"></TextBox>
<Button Content="Show" Click="Button_Click" Margin="5"></Button>
</StackPanel>
private void Button_Click(object sender, RoutedEventArgs e)
{
string str = this.FindResource("myString") as string; // FindResource返回object类型
this.textBox1.Text = str;
}
x:Shared
x:Key是把某些对象当作资源放进资源字典里,但每当它们检索到一个对象,我们得到的究竟是同一个对象还是这个对象的副本?这就由x:Shared
决定,它一定要与x:Key
配合使用,XAML默认x:Shared=true
,也就是说,默认情况下,我们得到的都是同一个对象。
x名称空间中的标记扩展
标记扩展实际上是一些MarkupExtension
类的直接或间接派生类,x名称空间中就包含有这样一些的类,所以常称它们为x名称空间的标记扩展。
x:Type
x:Type
在XAML中表达数据类型时就需要使用x:Type
标记扩展,比如某个类的属性,它的值要求是一种数据类型,当在XAML中为这个属性赋值时候,就要使用x:Type
。
//在MainWindow.xaml.cs中创建一个Button派生类
public class MyButton : Button
{
public Type UserWindowType { get; set; }
protected override void OnClick()
{
base.OnClick();
Window win = Activator.CreateInstance(this.UserWindowType) as Window;
if (win != null)
{
win.ShowDialog();
}
}
在项目中添加名为MyWindow
的Window
类型:
<StackPanel Background="LightBlue">
<TextBox Margin="5"/>
<TextBox Margin="5"/>
<TextBox Margin="5"/>
<Button Content="OK" Margin="5"/>
</StackPanel>
最后,把自定义按钮添加到主窗口的界面上,并把MyWIndow
作为一种数据类型赋值给MyButton.UserWindowType
属性。
<StackPanel>
<local:MyButton Content="Show" UserWindowType="{x:Type TypeName=local:MyWindow}" Margin="5">
</local:MyButton>
</StackPanel>
可见,对于UserWindowType
属性的赋值,需要其数据类型,所以必须在标记扩展中加上x:Type
。
而对于标记扩展的语法,因为TypeExtension
类的构造器可以接受数据类型名为其参数,所以可以简写为:
UserWindowType="{x:Type local:MyWindow}"
x:Null
在XAML中用来表示空值的是x:Null
.
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Width" Value="60"/>
<Setter Property="Height" Value="36"/>
<Setter Property="Margin" Value="5"/>
</Style>
</Window.Resources>
<StackPanel>
<Button Content="OK"/>
<Button Content="OK"/>
<Button Content="Ok" Style="{x:Null}"/>
</StackPanel>
其中,
<Style TargetType="Button">
</Style>
可以也可以写成
<Style TargetType="{x:Type Button}">
</Style>
标记扩展实例的两种声明语法
由于标记扩展也是标准的.NET类,所以完全也可以使用XAML标签来声明标记扩展的实例,比如上面的Button
Style
可以这样写:
<Button Content="Ok">
<Button.Style>
<x:Null/>
</Button.Style>
</Button>
x:Array
一下例子是把一个x:Array
的实例作为数据源提供给一个ListBox
:
<Grid Background="LightBlue">
<ListBox Margin="5">
<ListBox.ItemsSource>
<x:Array Type="sys:String">
<sys:String>Tim</sys:String>
<sys:String>John</sys:String>
<sys:String>Victor</sys:String>
</x:Array>
</ListBox.ItemsSource>
</ListBox>
</Grid>
必须以属性元素标签声明语法,而不能用标记扩展语法,因为如果是
ItemsSource="{x:Array Type=sys:String Items=XXXXX}"
是非法的,因为ArrayExtension
的Items属性是只读的。
x:XData
x:XData
标签是一个专用标签。WPF中把包含数据的对象称为数据源,用于把数据源中的数据提供给使用者的对象称为数据提供者。WPF类库中包含有多种数据提供者,其中有一个类叫XmlDataProvider
,专门用于提供XML化的数据。如果想在XAML里声明一个带有数据的XmlDataProvider
实例,那么XmlDataProvider
实例化的数据就要放在x:XData
标签的内容里。
<Window.Resources>
<XmlDataProvider x:Key="InvertoryData" XPath="Inventory/Books">
<x:XData>
<Supermarket xmlns="">
<Fruits>
<Fruit Name="peach"/>
<Fruit Name="Banana"/>
</Fruits>
</Supermarket>
</x:XData>
</XmlDataProvider>
</Window.Resources>