XAML使用标签来定义Ul元素(UIElement),每个标签对应NET Framework类库中的一个控件类。通过设置标签的Atribute,不但可以对标签所对应控件对象的Property进行赋值,还可以做一些额外的事件(如声明命名空间、指定类名等)。

树形结构

在界面上添加一些控件,界面如下:

界面的XAML如下所示:

<Window x:Class="LearnWpf.MainWindow"
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:LearnWpf"
mc:Ignorable="d"
Title="MainWindow" Height="164.458" Width="344.578">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="69*"/>
<ColumnDefinition Width="19*"/>
</Grid.ColumnDefinitions>
<TextBox HorizontalAlignment="Left" Height="23" Margin="10,33,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="245"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="10,91,0,0" VerticalAlignment="Top" Width="245" Height="21"/>
<StackPanel HorizontalAlignment="Left" Height="25" Margin="10,61,0,0" VerticalAlignment="Top" Width="245" Orientation="Horizontal">
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
</StackPanel>
<TextBox HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="245" />
</Grid>
</Window>

可以看出UI是平面结构,XAML是树形结构,而且同一种UI布局界面的XAML代码可以有多种实现。在开发时,可以通过WPF基本类库中的VisuaTreeHelper和LogicarTreeHelper两个助手类操作XAML树。

VS2019可以通过“视图->其他窗口->文档大纲”查看XAML代码的结构,如图所示:

对象属性赋值语法

XAML是一种声明性语言,在文档只能使用标签声明对象、初始化对象的属性。XAML中为对象属性赋值共有两种语法:

  • 使用字符串(标签的Attribute)进行简单赋值
  • 使用属性元素(Property Element)进行复杂赋值。

注:能使用Attribute=Value形式赋值的就不使用属性元素

使用标签的Attribute

一个标签的Attribute里有一部分与对象的Property互相对应,如<Rectangle>标签的Fill这个Attribute与Rectangle类对象的Fill属性对应。Rectangle.Fill的类型Brush是一个抽象类,凡是以Brush为基类的类都可作为Fill属性的值。

使用字符串对Atribute进行简单赋值,让Rectangle填充成单一的蓝色,XAML代码(省略了Window标签)如下:

<Grid>
<Rectangle x:Name="rectangle" Fill="Blue" HorizontalAlignment="Left" Height="100" Margin="70,17,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>
</Grid>

上面的“Blue”最终被翻译成了SolidColorBrush对象,等效C#代码如下:

SolidColorBrush sBrush = new SolidColorBrush();
sBrush.Color = Colors.Blue;
this.rectangle.Fill = sBrush;

使用属性元素

属性元素指的是某个非空标签的一个元素(夹在起始标签和结束标签之间的一些子级标签)对应这个标签的一个属性,即以元素的形式来表达一个实例的属性。

上面Attribute赋值的例子可以用属性元素的方式实现,XAML(省略了Window标签)代码如下:

<Grid>
<Rectangle x:Name="rectangle" HorizontalAlignment="Left" Height="100" Margin="70,17,0,0" Stroke="Black" VerticalAlignment="Top" Width="100">
<Rectangle.Fill>
<SolidColorBrush Color="Blue"/>
</Rectangle.Fill>
</Rectangle>
</Grid>

属性元素语法的优势在属性是复杂对象时才能体现出来,比如线性渐变画刷填充矩阵代码(省略了Window标签):

<Grid>
<Rectangle x:Name="rectangle" HorizontalAlignment="Left" Height="100" Margin="70,17,0,0" Stroke="Black" VerticalAlignment="Top" Width="100">
<Rectangle.Fill>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.2" Color="LightBlue"/>
<GradientStop Offset="0.7" Color="Blue"/>
<GradientStop Offset="1.0" Color="DarkBlue"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>

扩展:标记扩展(Markup Extensions)

上面大多数赋值都是为属性生成一个新对象,当需要为对象的属性进行特殊类型赋值时就需要使用标记扩展了,如:

  • 把同一个对象赋值给两个对象的属性
  • 给对象的属性赋一个null值
  • 将一个对象的属性值依赖在其他对象的某个属性上

标记扩展是一种特殊的Atribule=Value语法,Value字符串是由一对花括号及其括起来的内容组成,XAML编译器会对这样的内家做出解析并生成相应的对象。

使用Binding类的实例将TextBox的Text属性依赖在Slider的Value上,当Slider的滑块滑动时TextBox就会显示Slider当前的值,XAML代码(省略了Window标签)如下:

<Grid>
<StackPanel HorizontalAlignment="Left" Height="115" Margin="10,10,0,0" VerticalAlignment="Top" Width="205">
<TextBox Height="23" TextWrapping="Wrap" Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}"/>
<Slider x:Name="slider1" Margin="0,5,0,0"/>
</StackPanel>
</Grid>

Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}"就是标记扩展,对象的数据类型名是紧邻左花括号的字符串,对象的属性由一串以逗号连接的子字符串负责初始化(不加引号)

标记扩展也是对属性的赋值,完全可以使用属性标签的形式来替换标记扩展,但基本上没人这么做(太不简洁了)。

只有MarkupExtension类的派生类(直接或间接均可)才能使用标记扩展语法来创建对象,后面会主要说明下面几种:

  • MarkupExtension的直接派生类并不多,它们是:
  • System.Windows.ColorConvertedBitmapExtension
  • System.Windows.DynamicResourceExtension
  • System.Windows.ResourceKey
  • System.Windows.StaticResourceExtension
  • System.Windows.TemplateBindingExtension
  • System.Windows.ThemeDictionaryExtension
  • System.Windows.Data.BindingBase
  • System.Windows.Data.RelativeSource
  • System.Windows.Markup.ArrayExtension
  • System.Windows.Markup.NullExtension
  • System.Windows.Markup.StaticExtension
  • System.Windows.Markup.TypeExtension

扩展:使用TypeConverter 类映射Atribute与Property

有时候我们有一些自定义的类需要使用XAML语言进行声明,并允许它的Property与XAML标签的Atribute互相映射,那就需要为这些Property准备适当的转换机制

下面以自定义类Human为例演示TypeConverter的用法,XAML代码(省略了Window标签)如下:

<Window.Resources>
<local:Human x:Key="human" Child="AB" />
</Window.Resources>
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="61,40,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
//按钮事件
private void Button_Click(object sender, RoutedEventArgs e)
{
Human h = (Human)this.FindResource("human");
MessageBox.Show(h.Child.Name);
} /// <summary>
/// 以绑定转换器的目标类型Human(TypeConverter是TypeConverterAttribute的简写)
/// </summary>
[TypeConverter(typeof(StringToHumanlypeConverter))]
public class Human
{
public string Name { get; set; }
public Human Child { get; set; }
} /// <summary>
/// 字符串转目标类型Human的转换器
/// </summary>
public class StringToHumanlypeConverter : TypeConverter
{
//运行时转换源类型为此目标类型,缺少此方法的重载会使运行时类型转换异常
public override object ConvertFrom(ITypeDescriptorContext context, 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);
}
//设计时判断是否支持源类型到目标类型的转换,缺少此方法的重载会使UI设计器异常
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
}

需要注意的是TypeConverter的ConvertFrom、CanConvertFrom两个方法必须同时重载,只有前者会导致设计时界面异常、运行时数据转换正常,只有后者会导致设计时界面正常、运行时数据转换异常。

事件处理器

一个XAML标签对应着一个对象时,这个标签的一部分Atribute会对应这个对象的Property,还有一部分Attribute对应着对象的事件(Event)

标签有一个名为Click的Attribute,它对应的就是Buton类的Click事件,如下所示:

<Grid>
<Button x:Name="button1" Content="Button" HorizontalAlignment="Left" Margin="61,40,0,0" VerticalAlignment="Top" Width="75" Click="button1_Click"/>
</Grid>

注:右键Click="Button_Click"->“转到定义”,会自动生成一个空的事件处理函数

等效的C#代码如下所示:

Button buttonl = new Button();
buttonl.Click += new RoutedEventHandler(buton1_Click);

由于C#的partial类和XAML标签的x.Class特征,开发软件时完全可以把用于实现程序逻辑的C#代码放在一个文件里,把用于描述程序U1的XAML代码放在另一个文件里,并且让事件性Attribute充当XAML与C#之间沟通的纽带。这种将逻辑代码与UI代码分离、隐藏在UI代码后面的形式就叫作“代码后置”(Code-Behind)。当然,事件代码也可以使用标签x:Code直接写到XAML里面

导入程序集及引用命名空间

在XAML中引用命名空间的语法是:

xmlns:映射名="clr-namespace:类库中命名空间的名字;assembly=类库文件名"
  • xmlns是用于在XAML中声明命名空间的Attribute,从XML语言继承而来(XML Namespace的缩写)。
  • 冒号后的映射名是可选的,但由于可以不加映射名的默认命名空间已经被WPF的主要命名空间占用,所以所引用的命名空间都需要加上这个映射名。映射名可以自由选择,建议使用类库中命名空间的原名或者缩写
  • 引号中的字符串值确定了要引用的是哪个类库以及类库中的哪个命名空间。

使用引用命名空间中的类的语法如下:

<映射名:类名>.…</映射名:类名>

C#中也可以给命名空间设置映射名,但没什么意义,如:

using Cmn=Common;
using Cu=Controls;

XAML的注释

XAML的注释语法亦继承自XML,语法是:

<!--需要被注释掉的内容-->
  • XAML注释只能出现在标器的内容区域,即只能出现在开始标签和结来标签之阔。
  • XAML注释不能用于注释标签的Attribute。
  • XAML注释不能嵌套。

WPF之XAML语法的更多相关文章

  1. WPF 基础 - xaml 语法总结

    Attribute 与 Property 之间的区别 Property 对应着抽象对象身上的性状: Attribute 是针对标签的特征: 往往一个标签具有的 Attribute 对于它所代表的对象的 ...

  2. 4 WPF学习---系统的学习XAML语法

    转载:http://blog.csdn.net/fwj380891124/article/details/8093001 1,XAML文档的树形结构: UI在用户眼里面是个平面结构.如下图所示,在用户 ...

  3. XAML属性赋值转换之谜(WPF XAML语法解密)

    XAML与XML类似,就是XML延伸过来的.为了更好的表达一些功能,WPF对XML做了扩展,有些功能是WPF在后台悄悄的替你做了.有时候,虽然实现了某个功能,但是对实现原理还是很茫然.今天就讲讲XAM ...

  4. WPF中 PropertyPath XAML 语法

    原文:WPF中 PropertyPath XAML 语法 PropertyPath 对象支持复杂的内联XAML语法用来设置各种各样的属性,这些属性把PropertyPath类型作为它们的值.这篇文章讨 ...

  5. WPF:XAML概述

    简介 XAML是eXtensible Application Markup Language可扩展应用程序标记语言,它是微软公司为构建应用程序用户界面而创建的一种新的描述性语言.XAML提供了一种便于 ...

  6. wpf中xaml的类型转换器与标记扩展

    原文:wpf中xaml的类型转换器与标记扩展 这篇来讲wpf控件属性的类型转换器 类型转换器 类型转换器在asp.net控件中已经有使用过了,由于wpf的界面是可以由xaml组成的,所以标签的便利也需 ...

  7. .Net Core WPF之XAML概述

    原文链接,机器翻译,有误处参看原文. XAML overview in WPF 2019/08/08 What is XAML XAML syntax in brief Case and white ...

  8. Xaml语法概述及属性介绍

    Xaml语法概述 1.命名空间     xmal每个元素都对应着一个类,但是在xmal中,只提供类名是不够的,需要知道该类实在.net的哪个命名空间下面.Xaml解析器才能够正确的解析. 1 < ...

  9. 基本 XAML 语法指南

    我们介绍了 XAML 语法规则,以及用于描述 XAML 语法中存在的限制或选项的术语.当出现以下情况时你会发现本主题很有用:不熟悉 XAML 语言的使用,希望加强对术语或某些语法部分的理解,或者对 X ...

  10. How can I list colors in WPF with XAML?

    How can I get list of all colors I can pick in Visual Studio Designer (which is System.Windows.Media ...

随机推荐

  1. 程序设计实验第一学期期末考试复习用源代码【C语言深度解剖】【超详细注释】

    有关此篇 在这里博主先告诉大家,博主在学校学的C语言课本是<谭浩强的C语言>那这本红色的书. 博主到期末阶段是学到了结构体那一章,下面是博主的复习代码,是一些比较有编程思想的一些源代码,博 ...

  2. PHP中文件锁

    PHP中文件锁 文件锁的用途: 若一个人在写入一个文件,另外一个人同时也打个了这个文件进行写入文件. 这情况下,如果遇到一定的碰撞概率的话,不知道到底谁的操作为准. 因此,这个时候我们引入锁机制. 若 ...

  3. 使用Visual studio code 进行.NET 开发

    Visual studio code 作为一款强大的编辑器,相信很多开发者都用过.vs code 的强大源自开源生态丰富,编辑器本身简单,但是加上各式的插件,就变得无比牛逼,基本可以替代现有的大部分工 ...

  4. Hbase简单介绍

    一.背景介绍 我们生活在一个互联网的时代,这个时代的特点是,无论任何事情,只要我们想知道,都可以通过互联网迅速的检索到问题的答案,并且答案是有用的,并非常切合我们的需要. 因此,很多公司都开始致力于提 ...

  5. C++——异常处理模块笔记

    异常处理是C++中的重要概念之一,用于处理在程序执行过程中可能发生的错误或异常情况.异常是指在程序执行过程中发生的一些不寻常的事件,例如除零错误.访问无效内存等.C++提供了一套异常处理机制,使得程序 ...

  6. ABC 309

    直接从 F 开. F 三维偏序. 把盒子按 \(h_i\) 排序,离散化,正常跑三维偏序(注意不能相等). 还要处理 \(h_i\) 相等的情况,可以再把 \(h_i\) 从大到小排序,然后 \(w_ ...

  7. C# 实现刘谦春晚魔术

    internal class Program { static List<string> list=new List<string>() { "A",&qu ...

  8. NC20240 [SCOI2005]互不侵犯KING

    题目链接 题目 题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案. 国王能攻击到它上下左右,以及左上 左下右上右下八个方向上附近的各一个格子,共8个格子. 输入描述 只有一行 ...

  9. GCC Arm 11.3rel1, 12.2编译提示 _close is not implemented and will always fail

    使用GCC Arm工具链开发的项目, 在11.2下编译正常, 但是升级到 arm-gnu-toolchain-11.3.rel1 以及 arm-gnu-toolchain-12.2 之后, 编译出现警 ...

  10. Laravel入坑指南(9)——数据迁移与填充

    当我们开发完成一个(小)项目,发布到线上时,我们需要将本地数据库迁移到服务器上,并且填充初始化数据.而Laravel框架规定了一套完善的数据迁移与填充机制. 在官网中分别介绍了以下四个命令: php ...