WPF学习笔记“XAML”一:基础
一 XAML包括的几个子集:
1 WPF XAML包含描述WPF内容的元素,如矢量图形 控件以及文档.目前,它是最重要的XAML应用;
2 XPS XAML是WPF XAML的一部分,它为格式化的电子文档定义了一种XML表示方式.XPS XAML已经作为单独的XML页面规格标准发布;
3 Silverlight XAML是一个用于Silverlight应用程序的WPF XAML子集;
4 WF XAML包括描述Windows工作流基础(WF)内容的元素.
二 XAML编译
WPF的创造者知道XAML不仅要能够解决设计合作问题,它还需要运行得比较快;WPF使用BAML(二进制应用程序标记语言)来消除这一个缺点.BAML实际上就是XAML的二进制表示.当在visual studio中编译WPF应用程序时,所有XAML文件都被转换为BAML,并且这些BAML然后作为资源被嵌入到最终的DLL或EXE程序中.BAML是标记化的,这意味着较长的XAML被较短的标记代替.
三 XAML基础规则
1 在XAML文档中的所有元素都映射为一个.net类的实例.元素的名称也完全对应于类名.例如:元素<button>指示WPF创建一个button对象;
2 与所有XML文档一样,可以在一个元素中嵌套另一个元素.在一个Grid元素中发现一个button元素.
3 可以通过特性(attribute)设置每个类的属性,但是,在某些情况下,特性不足以完成这一工作.对于这些情况,需要通过特殊的语法使用嵌套的标签(tag).
四 XAML名称空间
显然,只有类名是不够的,XAML解析器还需要知道类位于哪个名称空间.
<Window x:Class="Picture.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:Picture"
xmlns特性是XML中的一个特殊的特性,它专门用于声明名称空间.这段标签声明了两个名称空间,在创建的所有WPFXAML文档中都会使用这两个名称空间:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"是WPF核心名称空间.它包含了所有WPF类,包括用于构建用户界面的控件.在这个示例中,该名称空间的声明没有使用名称空间前缀,所以它成为整个文档的默认名称空间.换句话说,除非另行指名,每个元素自动位于这个名称空间.
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"是XAML名称空间,它包含各种XAML实用特性,这些特性会影响文档的解释方式.这个名称空间被映射为前缀x;这意味着可以通过在元素名称之前放置一个名称空间前缀来使用这个名称空间(例如<x:ElementName)
五 代码隐藏类
<Window x:Class="Picture.MainWindow"
在XAML名称空间的Class特性之前放置了名称空间前缀x,意为着这是XAML语言中更通用的部分.部分上,Class特性告诉XAML解析器使用指定的名称生成一个新类.该类继承了自由XML元素命名的类,换句话说,这个示例创建了一个名为MainWindow的新类.该类继承自window基类;
MianWindow类是在编译时自动生成的.这正是问题的关键所在.可以提供MianWindow的部分类,该部分类会和自动生成的那部分合并在一起.自己提供的部分类正式包含事件处理程序代码的理想容器;
六 后台代码
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
如果自己定义的构造函数也同时要确保调用InitializeComponent();
本质上InitializeComponent()方法的所有工作就是调用System.Windows.Application类的LoadComponent()方法。LoadComponent()方法从程序集中提取BAML,
并使用它构建用户界面。当解析BAML时,它会创建每个控件对象,设置其属性,并关联所有事件处理程序;
七 命名元素
<Grid x:Name = "GridName"></Grid> 与 <Grid Name = "GridName"></Grid> 等价
Name特性是告诉XAML解析器将这样一个字段添加到MainWindow类自动生成的部分: private System.Windows.Controls.Grid GridName;
现在可以在MainWindow类的代码中,通过GridName名称进行交互;
WPF中的控件可以没有Name特性,WindowForm中的空间必须有Name特性;
八 特性
1 简单属性和类型转换器
其中类型转换器Foreground=“White” 和Foreground= “white”是等价的;
2 属性元素语法(XAML代码)
使用属性元素法,可添加一个其名称形式为Parent.PropertyName的子元素。例如:Grid控件有一个Backgound属性,该属性允许提供一个用于绘制控件背景区域的画刷
例如:
<Grid>
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.00" Color="Red"></GradientStop>
<GradientStop Offset="0.50" Color="Indigo"></GradientStop>
<GradientStop Offset="1.00" Color="Violet"></GradientStop>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
</Grid>
是使用一个复杂的画刷比单一固定颜色填充更高级的画刷,就需要添加这个属性;
3 后台代码
LinearGradientBrush brush = new LinearGradientBrush();
GradientStop gradientstop1 = new GradientStop();
gradientstop1.Offset = 0;
gradientstop1.Color = Colors.Red;
brush.GradientStops.Add(gradientstop1);
GradientStop gradientstop2 = new GradientStop();
gradientstop2.Offset = 0.5;
gradientstop2.Color = Colors.Indigo;
brush.GradientStops.Add(gradientstop2);
GradientStop gradientstop3 = new GradientStop();
gradientstop3.Offset = 1;
gradientstop3.Color = Colors.Violet;
brush.GradientStops.Add(gradientstop3);
grid.Background = brush;
与之前的XAML实现相同的效果
九 标记扩展
对于大多数属性,XAML属性语法可以工作得非常好,但是在有些情况下,不可能硬编码属性值,例如,可能希望将属性设置为一个已经存在的对象,或者可能希望通过
将一个属性绑定到另一个控件来动态地设置属性值。对于这两种情况,需要使用标记扩展----一种以非常规的方式设置属性的专门语法;
标记扩展可用于嵌套标签或XML特性中,当用于特性中时,它们总是被花括号{}包围起来,例如,下面的标记演示了如何使用StaticExtension标记扩展,它允许引用另一个类中的静态属性: <Button Foreground = "{x:Static SystemColor.ActiveCaptionBrush}">
标记扩展使用{标记扩展类 参数}语法。标记扩展是StaticExtension类,x前缀指示在一个XAML名称空间中查找StaticExtension类,还有一些标记扩展是WPF名称空
间的一部分,它们不需要x前缀。
所有标记扩展都是继承自system.windows.markup.markupextension基类的类实现。markupextension基类非常简单,它提供了一个简单的ProvideValue()方
法,该方法获取所期望的数值。
后台代码: BtnName.Foreground = SystemColors.ActiveCaptionBrush;
也可以使用前面所提到的方式:
<Button>
<Button.Foreground>
<x:static Member = "SystemColors.ActiveCaptionBrush"></x:Static>
</Button.Foreground>
</Button>
根据标记扩展的复杂度,以及想要设置的属性的数量,这种语法有时更简单。这种方法多在使用资源和数据绑定时;
十 附加属性
附加属性可以用于多个控件但在另一类中定义的属性。在WPF中,附加属性经常用于控件布局。
下面是附加属性的原理,每个控件都有自己的固有属性,当在容器中放置一个控件时,根据容器的类型控件获得额外的特征。
附加属性总是使用包含两个部分的命名形式: 定义类型.属性名。这种包含两个部分的命名语法,使XAML解析器能够区分普通的属性和附加属性;
<Button Grid.Row = "1">
</Button>
附加属性根本不是真正的属性,它们实际上被转换为方法调用。XAML解析器以下面这种形式调用静态方法:DefiningType.SetPropertyName()。例如,在上面的XAML
标记中,定义类型是Grid类,并且属性是Row,所以解析器调用Grid.SetRow()方法;当为TextBox控件设置Grid.Row属性时,XAML解析器执行以下代码:
后台代码:Grid.SetRow(BtnName,0);
后台代码:BtnName.SetValue(Grid.Rowproperty,0);
十一 嵌套元素
XAML让每个元素决定如何处理嵌套的元素。这种交互使用下面三种机制中的一种进行中转,并且求值得顺序也是下面列出这三种机制的顺序:
1 如果父元素实现了IList接口,解析器就会调用IList.Add()方法,并且为该方法传入子元素作为参数。
2 如果父元素实现了IDictionary接口,解析器就会调用IDictionary.Add()方法,并且为该方法传递子元素作为参数。当使用字典集合时,还必须设置x:key特性以便为
每个条目指定一个键名;
3 如果父元素使用ContentProperty特性进行了修饰,则解析器使用子元素设置对应的属性;
<Grid Grid.Row="0">
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.00" Color="Red"></GradientStop>
<GradientStop Offset="0.50" Color="Indigo"></GradientStop>
<GradientStop Offset="1.00" Color="Violet"></GradientStop>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
</Grid>
如果集合默认为null,则需要包含用于指定集合类的标签,以此创建一个集合对象,如果有一个默认的集合实例并且指示需要为它填充元素,则可以忽略这一部分;
Grid不是集合类,没有实现相应的接口,它继承与panel类;
十二 事件
所有的特性都能被映射为属性;事件名 = “事件处理程序方法名” <Button Click = "Btn_Click"></Button>
十三 使用其他名称空间中的类型
xmlns:Prefix = "clr-namespace:Namespace;assenbly=AssemblyName"
通常,在XAML文档的根元素中,在紧跟声明WPF和XAML名称空间的特性之后,放置这个名称空间。
其中:prefix是名称空间的XML前缀; Namespace是完全限定的.net名称空间的名称; AssemblyName是声明类型的程序集,没有.dll扩展名
xmlns:sys="clr-namespace:System; assembly=mscorlib"
xmlns:local="clr-namespace:MyNamespace"
现在使用名称空间的类的实例: <local:MyClass></local:MyClass>
十四 引用 内置类型 未编译的XAML 编译过的XAML
待续
十五 高级对象的创建
后台代码:
public class Person
{
public string FirstName{get;set;}
public string LastName{get;set;}
public Person(string FirstName, string LastName)
{
FirstName = firstName;
LastName = lastName;
}
}
使用XAML可以像下面那样初始化该类
<local:Person>
<x:Arguments>
<x:String>Joe</x:String>
<x:String>McDowell</x:String>
</x:Arguments>
</local:Person>
高级对象的创建 待续