什么是XAML?
基于XML的.NET对象标记语言,在这里用于构造WPF用户界面。
设计目的在于前后端分离,与HTML类似。
XAML在编译的时候可能会转换为BAML(二进制应用程序标记语言),以便于更快解析。
XAML的一些子集:
WPF XAML、XPS XAML、SilverLight XAML(淘汰)、WF XAML。跨移动端平台的MAUI技术,也是使用XAML。
XAML语法
标签语言,可嵌套,可设置属性
<Window x:Class="Demo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Demo"
mc:Ignorable="d"
Title="Window1" Height="450" Width="800">
<Grid>
</Grid>
</Window>
每个XAML文档中只能有一个顶级元素,如Window、Page、Application等。
可设置属性,如Title="Window1" Height="450" Width="800"
命名空间 xmlns-xml namespace
WPF核心命名空间xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
XAML命名空间xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
代码隐藏类
namespace Demo
{
/// <summary>
/// Window1.xaml 的交互逻辑
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
部分类(partial class)是事件处理程序代码(C#代码)的理想容器。
默认构造函数InitializeComponent(),作用是调用System.Windows.Application类的LoadComponet()方法,从程序集中BAML(编译过的XAML)来构建用户界面。
<Grid x:Name="testName">
</Grid>
<Grid Name="testName">
</Grid>
x:Name="xxx" 和 Name= "xxx",两种命名方式最终效果等价,但x:Name可命名任何元素,Name仅能命名有Name属性的元素。
XAML属性和事件
<TextBlock VerticalAlignment="Top" HorizontalAlignment="Left" FontSize="16"/>
如VerticalAlignment、HorizontalAlignment、FontSize是控件TextBlock的属性。
属性设置生效的过程中,XAML解析器分步骤查找类型转换器TypeConverter将字符串值与非字符串类型的属性相关联。
XAML区分大小写<Button/>不能写成<button/>
类型转换器通常不区分大小写,Foreground="white" 和 Foreground="White" 同样生效。
属性元素语法-设置复杂的属性
<Grid>
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.00" Color="Red"/>
<GradientStop Offset="0.50" Color="Indigo"/>
<GradientStop Offset="1.00" Color="Violet"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
</Grid>
也可使用C#代码在.cs文件中通过Name命名后的对象操作实现。
LinearGradientBrush b = new LinearGradientBrush();
GradientStop g1 = new GradientStop();
g1.Offset = 0;
g1.Color = Colors.Red;
b.GradientStops.Add(g1);
GradientStop g2 = new GradientStop();
g2.Offset = 0.5;
g2.Color = Colors.Indigo;
b.GradientStops.Add(g2);
GradientStop g3 = new GradientStop();
g3.Offset = 0;
g3.Color = Colors.Violet;
b.GradientStops.Add(g3);
grid111.Background = b;
标记扩展
作用是可以将属性值设置为一个已存在对象或进行动态绑定。
<TextBlock Background="{x:Static SystemColors.ActiveBorderBrush}"/>
与代码赋值的结果一样
xxx.Backgroud = SystemColors.ActiveBorderBrush;
也可使用C#代码在.cs文件中通过Name命名后的对象操作实现。
还可以利用标记扩展是类的特点,进行嵌套属性写法。
<TextBlock Text="123">
<TextBlock.Background>
<x:Static Member="SystemColors.ActiveBorderBrush"/>
</TextBlock.Background>
</TextBlock>
附加属性
<TextBlock x:Name="testTb" Grid.Row="0"/>
例如:Grid.Row="0" 会被XAML解析器调用Grid.SetRow()静态方法。 DefiningType.SetPropertyName()
其中还会有两个必要参数,元素对象和属性值,即会执行Grid.SetRow(testTb,0);
附加属性的技术基础是控件都是继承自DependencyObject基类,Grid.SetRow()其实是DependencyObject.SetValue()的简化写法。
更本质的代码是testTb.SetValue(Grid.RowProperty,0);
嵌套元素
有三种机制,根据父元素实现的接口类型,解析器将进行不同的操作。
- 父元素实现IList,解析器调用IList.Add()
- 父元素实现IDictionary,解析器调用IDictionary.Add(),同时为每个条目设定了x:Key特性
- 父元素实现ContentProperty,解析器使用子元素设置对应属性
集合类嵌套元素的写法,即上面提到的属性元素语法的使用。
这里需要注意的是,如果集合默认为null,需要标签声明指定集合类型<GradientStopCollection></GradientStopCollection>,存在值时则允许省略,即如下写法。
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.00" Color="Red"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
继承ContentProperty的控件使用,例如:<TextBlock>你好啊</TextBlock>
特殊字符与空白
小于号 <
大于号 >
&符号 &
"引号 "
<TextBlock xml:space="preserve"> 你 好 啊 </TextBlock>
xml:space="preserve"将保留空白和硬回车,默认情况下空格和硬回车会被清除,当然这仅限于在XAML中设置文本,通过Binding或者C#代码设置,会将空格和硬回车都保留下来。
事件
<Button x:Name="test_btn" Click="test_btn_Click"/>
private void test_btn_Click(object sender, RoutedEventArgs e)
{
//操作
//处理Sender和e对象,可以获得与动作和源控件的一些信息。
}
使用其他命名空间的类型
与xmlns:local="clr-namespace:Demo"这种写法类似
例如xmlns:myself="clr-namespace:XXX"
加载和编译XAML
有三种不同的编码方式创建WPF应用程序
- 只用C#代码
- 使用代码和未经编译的标记(XAML),在C#代码中通过文件流读取XAML文件,然后用进行对象处理操作
- 使用代码和编译过的标记(BAML),用C#代码直接加载编译好的BAML
只使用XAML
类似静态HTML,可以通过构建XBAP应用程序在浏览器中使用。