XAML赋值方法
XAML中为对象属性赋值共有两种语法:
- 使用字符串进行简单赋值
- 使用属性元素(Property Element)进行复杂赋值。
通过字符串的形式进行赋值:
用属性元素的方式进行改写赋值:
选择为对象属性赋值的语法时,对于简单赋值而言属性元素语法并没有什么优势,但遇到属性是复杂对象时这种语法的优势就发挥出来了。
LinearGradientBrush 的 GradientStops 属 性 是 一 个 GradientStop 对 象 的 集 合(GradientStopCollection),即一系列的矢量渐变填充点。在这些填充点之间,系统会自动进行插值运算、计算出过渡色彩。填充矢量的方向是StartPoint和EndPoint两个属性(类型为Point)的连线方向,矩形的左上角为0,0、右下角为1,1。这段代码中,针对这三个属性都使用了属性标签式赋值方法。
古语道:“过犹不及”。上面的代码为了突出属性元素语法我将所有属性都展开成属性元素,结果是代码的可读性一落千丈。经过优化,代码变成这样(少了三分之一):
注意
这里有几个简化XAML的技巧:
- 能使用Attribute=Value形式赋值的就不使用属性元素。
- 充分利用默认值,去除冗余:StartPoint=“0,0”,EndPoint="1,1"是默认值,可以省略。
- 充分利用XAML的简写方式:XAML的简写方式有很多,需要在实际工作中慢慢积累。
比如本例LinearGradientBrush.GradientStops 的数据类型是 GradientStopCollection,如果严格按照语法来写,这个属性元素的内容应该是一个标签,实际上,XAML允许你省略这个标签而把集合元素直接写在属性元素的内容里。
Property和Attribute
Property理解为对象的属性,本质上是访问字段提供的一种封装方法(get/set)。
Attribute是对象的特性,本质上是一个类,其为目标元素提供关联附加信息,并在运行期以反射的方式来获取附加信息。它的作用更类似于注释。
下面我们用代码来说明Attribute
- 自定义Attribute类:VersionAttribute
[AttributeUsage(AttributeTargets.Class)]
public class VersionAttribute : Attribute
{
public string Name { get; set; }
public string Date { get; set; }
public string Describtion { get; set; }
}
- 使用自定义Attribute的Class:
[Version(Name = "hyddd", Date = "2009-07-20", Describtion = "hyddd's class")]
public class MyCode
{
//...
}
- 上面这个Class中的Attribute一般会被如何使用呢?
class Program
{
static void Main(string[] args)
{
var info = typeof(MyCode);
var classAttribute = (VersionAttribute)Attribute.GetCustomAttribute(info, typeof(VersionAttribute));
Console.WriteLine(classAttribute.Name);
Console.WriteLine(classAttribute.Date);
Console.WriteLine(classAttribute.Describtion);
}
}
标记扩展
所谓标记扩展,实际上是一种特殊的Attribute=Value语法,其特殊的地方在于Value字符串
是由一对花括号及其括起来的内容组成,XAML编译器会对这样的内容做出解析、生成相
应的对象。
其中,Text="{Binding ElementName=slider1, Path=Value, Mode=OneWay}"这句就是标记扩
展了。我们分析一下这句代码:
- 当编译器看到这句代码时就会把花括号里的内容解析成相应的对象。
- 对象的数据类型名是紧邻左花括号的字符串。
- 对象的属性由一串以逗号连接的子字符串负责初始化(注意,属性值不再加引号)。
注意以下几点
-
标记扩展是可以嵌套的,例如Text="{Binding Source={StaticResource myDataSource},
Path=PersonName}"是正确的语法。 -
标记扩展具有一些简写语法,例如"{Binding Value,…}“与”{Binding Path=Value,…}“是
等价的、”{StaticResource myString,…}“与”{StaticResource ResourceKey=myString,…}"是等
价的。 -
标记扩展类的类名均以单词Extension为后缀,在XAML使用它们的时候Extension后缀可
以省略不写,比如写Text="{x:Static…}“与写Text=”{x:StaticExtension…}"是等价的。
x名称空间
x名称空间可以分为Attribute、标记扩展和XAML指令元素三类。
x名称空间中的Attribute
x:Class
这个Attribute的作用是告诉XAML编译器将XAML标签的编译结果与后台代码中指定的类合
并。在使用x:Class时必须遵循以下要求:
- 这个Attribute只能用于根结点。
- 使用x:Class的根结点的类型要与x:Class的值所指示的类型保持一致。
- x:Class的值所指示的类型在声明时必须使用partial关键字。
x:ClassModifier
这个Attribute的作用是告诉XAML编译由标签编译生成的类具有怎样的访问控制级别。
x:Name
x:Name的作用有两个:
-
告诉XAML编译器,当一个标签带有x:Name时除了为这个标签生成对应实例外还要
为这个实例声明一个引用变量,变量名就是x:Name的值。 -
将XAML标签所对应对象的Name属性(如果有)也设为x:Name的值,并把这个值注 册到UI树上,以方便查找。
x:FieldModifier
在XAML里改变引用变量访问级别的。
x:Key
x:Key的作用就是为资源贴上用于检索的索引。
x:Shared
x:Shared一定要与x:Key配合使用,如果x:Shared的值为true,那么每次检索到这个对象时,我们得到的都是同一个对象,否则如果x:Shared的值为false,每次我们检索到这个对象时,我们得到的都是这
个对象的一个新副本。
x名称空间中的标记扩展
x:Type
当我们在XAML中想表达某个数据类型时就需要使用x:Type标记扩展。比如某个类的一个
属性,它的值要求是一种数据类型,当我们在XAML为这个属性赋值时就要使用x:Type。
x:Null
不想要默认值时,可设置为null值。
标记扩展实例的两种声明语法
花括号、标签式声明。
x:Array
x:Array的作用就是通过它的Items属性向使用者暴露一个类型已知的ArrayList实例,
ArrayList内成员的类型由x:Array的Type指明。
x:Static
注意
如果一个程序需要国际化支持,一般会把需要显示的字符串保存在一个资源类的static属性
中,所以支持国际化的程序UI中对x:Static的使用非常频繁。
x名称空间中的XAML指令元素
XAML指令元素只有两个
- x:Code
- x:XData
x:Code
它的作用就是可以包含一些本应放置在后置代码中的C#代码。这样做的好处是不用把XAML代码和C#代码分置在两个文件中,但若不是遇到某些极端环境我想应该没人这么干,这样做最大的问题就代码不好维护、不易调试。
x:XData
WPF类库中包含多种数据提供者,其中有一个类叫XmlDataProvider,专门用于提供XML化的数据。
如果想在XAML里声明一个带有数据的XmlDataProvider实例,那么XmlDataProvider实例的数据就要
放在x:XData标签的内容里。
WPF布局元素
WPF中的布局元素有如下几个:
- Grid:网格。可以自定义行和列并通过行列的数量、行高和列宽来调整控件的布局。近 似于HTML中的Table。
- StackPanel:栈式面板。可将包含的元素在竖直或水平方向上排成一条直线,当移除一 个元素后,后面的元素会自动向前移动以填充空缺。
- Canvas:画布。内部元素可以使用以像素为单位的绝对坐标进行定位,类似于Windows Form编程的布局方式。
- DockPanel:泊靠式面板。内部元素可以选择泊靠方向,类似于在Windows Form编程中 设置控件的Dock属性。
- WrapPanel:自动折行面板。内部元素在排满一行后能够自动折行,类似于HTML中的 流式布局。