XAML使用树形结构来描述UI。
一、为对象属性赋值
XAML是一种声明性语言,XAML编译器会为每个标签创建一个与之对应的对象,注意是对象。对象创建后要对它的属性进行必要的初始化后才会有意义。因为XAML语言不能编写程序的运行逻辑,所以一份XAML文档中除了使用标签声明对象外就是初始化对象的属性。
XAML中为对象属性赋值有两种方式:
1、使用字符串进行简单赋值
2、使用属性元素(Property Element)进行复杂赋值
使用标签的Attribute为对象属性进行赋值
一个标签的Attribute里有一部分与对象的Property相对应。<Rectangle>标签的Fill这个Attribute就与Rectangle类的Fill属性相对应。Fill属性的类型是一个抽象类型Brush,凡是以Brush为积累的类都可以作为Fill属性的值。
首先是简单的使用使用字符串对Attribute进行简单赋值:
<Rectangle x:Name="rectangle" Width="200" Height="120" Fill="Blue"/>
但这种Attribute=value的赋值方式,value只能是字符串。
所以,如果要把一个类使用xaml进行声明,并允许其Property和xaml标签的Attribute互相映射,就需要Property准备适当的转换机制。(解决办法是:TypeConverter派生类)
又或者,由于字符串格式复杂程度有限,尽管可以在转换机制里包含一定的按格式解析字符串转换为较复杂的目标对象,但这会使xaml变得复杂。(解决办法是:属性元素)
2种解决办法补充:(这两种解决办法一般是不需要的,仅用于了解)
首先为窗体添加一个按钮,为项目添加一个Human类,并在xaml绑定资源
<Window.Resources> <local:Human x:Key="human" Name="JingYe"/> </Window.Resources> ... public class Human { public string Name { get; set; } public Human Child { get; set; } } ... private void btnChild_Click(object sender, RoutedEventArgs e) { Human h = (Human)this.FindResource("human"); MessageBox.Show(h.Child.Name); }
然后在xaml.cs中添加TypeConverter派生类将xaml标签Attribute与对象Property进行映射
public class StringToHumanTypeConventer:TypeConverter { public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { if(value is string) { Human h = new Human(); h.Name = value as string; return h; } return base.ConvertFrom(context, culture, value); } }
然后在Human类上加上特性,注意是TypeConverterAttribute
[TypeConverterAttribute(typeof(StringToHumanTypeConventer))] public class Human { public string Name { get; set; } public Human Child { get; set; } }
此时,就可以正确显示
<local:Human x:Key="human" Child="ABC" Name="JingYe"/>
Child所对应的JingYe。但一般情况下,最常用写法还是:
<local:Human x:Key="human" Name="JingYe"/>
...
第二种办法是属性元素:
xaml中,非空标签均具有自己的内容。标签的内容指的是夹在起始标签和结束标签之间的一些子级标签,每个子级标签都是父级标签的一个元素。也就是说,属性元素指的是某个标签的一个元素对应这个标签的一个属性,即以元素的形式来表达一个实例的属性。
<ClassName>
<ClassName.PropertyName>
<!--以对象形式为属性赋值-->
</ClassName.PropertyName>
</ClassName>
所以之前的<Rectangle>元素也可以写成:
<Rectangle x:Name="rectangle" Width="200" Height="120"> <Rectangle.Fill> <SolidColorBrush Color="Blue"/> </Rectangle.Fill> </Rectangle>
这种属性元素对简单属性没有什么帮助,但对于复杂对象属性就很有帮助。例如:
<Rectangle x:Name="rectangle" Width="200" Height="120"> <Rectangle.Fill> <LinearGradientBrush> <LinearGradientBrush.StartPoint> <Point X="0" Y="0"/> </LinearGradientBrush.StartPoint> <LinearGradientBrush.EndPoint> <Point X="1" Y="1"/> </LinearGradientBrush.EndPoint> <LinearGradientBrush.GradientStops> <GradientStopCollection> <GradientStop Offset="0.2" Color="LightBlue"/> <GradientStop Offset="0.7" Color="Blue"/> <GradientStop Offset="1.0" Color="DarkBlue"/> </GradientStopCollection> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Fill> </Rectangle>
渲染出来的xaml是一个渐变色的矩形。还可以简化为:
<Rectangle x:Name="rectangle" Width="200" Height="120"> <Rectangle.Fill> <LinearGradientBrush> <LinearGradientBrush.GradientStops> <GradientStopCollection> <GradientStop Offset="0.2" Color="LightBlue"/> <GradientStop Offset="0.7" Color="Blue"/> <GradientStop Offset="1.0" Color="DarkBlue"/> </GradientStopCollection> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Fill> </Rectangle>
简化技巧:
1、能使用Attribute=Value形式赋值就不使用属性元素
2、充分利用默认值,去除冗余:比如StartPoint="0,0",EndPoint="1,1"就是默认值可以省略
3、充分利用简写形式
标记扩展:
xaml中为对象属性赋值的语法,大多数赋值都是在为属性生成一个新对象,但也有时会需要把同一个对象赋值给两个对象的属性,还有的时候需要给对象的属性赋一个null值,WPF甚至还允许把一个对象的属性值依赖在其他对象的某个属性上。当需要为对象的属性进行这些特殊类型赋值时,就会需要使用标记扩展。
<TextBox Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}" Margin="5"/> <Slider x:Name="slider1" Margin="5"/>
Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}"就是标记扩展。
1、编译器看到这句代码时,会把花括号中的内容解析成相应的对象
2、对象的数据类型名是紧邻左边花括号的字符串
3、对象的属性由一串以逗号连接的子字符串负责初始化
它实际上很类似对象初始化器的写法:
Binding binding=new Binding(){Source=slider1,Mode=BindingMode.OneWay};
使用标记扩展时,要注意以下几点:
1、标记扩展可以嵌套,例如Text="{Binding Source={StaticResources myResources},Path=PersonName}"
2、标记扩展可以由一些简写语法,例如{Binding Value,...}等价于{Binding Path=Value,...},{StaticResource myString,...}等价于{StaticResource ResourceKey=myString,...}
3、标记扩展的类名均以Extension为后缀,在xaml使用的时候可以省略不写