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. Linux下的gcc/g++编译器的使用 [补档-2023-06-13]

    gcc编译器 ​ 这东西是Linux上的c/c++编译器. 5-1 gcc的工作流程 5-2 gcc的常用参数 -v 查看gcc版本号, --version也可以 -E 生成预处理文件 -S 生成汇编 ...

  2. ChatGPT 对接微信公众号技术方案实现!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 9天假期写了8天代码和10篇文章,这个5.1过的很爽! 如假期前小傅哥的计划一样,这个假期开启 ...

  3. 如何修改OSW图表中显示的主机名称

    本次测试的OSW版本:831 有人可能会说这种需求是吃饱了撑的吗,谁没事儿改这个名称干嘛啊? 其实并不是,因为有些生产案例非常典型,分享讲解时也需要配合OSW的趋势图来展示,但是出于保护客户隐私(哪怕 ...

  4. delphi 设置一个控件 在一个窗口的 正中间 方法

    1.选中控件,右键----postion--  最下面两个 x y 坐标,center in window

  5. .NET Core开发实战(第26课:工程结构概览:定义应用分层及依赖关系)--学习笔记

    26 | 工程结构概览:定义应用分层及依赖关系 从这一节开始进入微服务实战部分 这一节主要讲解工程的结构和应用的分层 在应用的分层这里定义了四个层次: 1.领域模型层 2.基础设施层 3.应用层 4. ...

  6. scrapy框架使用:分布式、增量式

    scrapy框架的使用 前记:爬虫框架部分整理完成,后续慢慢完善, 声明: 1)仅作为个人学习,如有冒犯,告知速删! 2)不想误导,如有错误,不吝指教! 创建工程: scrapy startproje ...

  7. 致敬英雄,共悼逝者,css 让页面变黑白

    壹 ❀ 引 今天是四月四日清明节,也是全国哀悼抗疫烈士的一天.细心的同学可以发现,不仅是娱乐活动以及游戏全部停止,当我们打开各大门户网站,网站页面也都变成了黑白,那么具体怎么做呢,这里可以借用CSS3 ...

  8. NC210981 mixup2混乱的奶牛

    题目链接 题目 题目描述 混乱的奶牛 [Don Piele, 2007] Farmer John的 N(4 <= N <= 16) 头奶牛中的每一头都有一个唯一的编号 \(S_i (1 & ...

  9. NC16664 [NOIP2004]合唱队形

    题目链接 题目 题目描述 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2-,K,他们的身高分 ...

  10. 详解最新版RabbitMQ 基于RPM 方式的安装

    如何选择安装版本 已经不支持的发布系列 版本 最后补丁版本 首次发布时间 停止更新时间 3.7 3.7.28 2017年11月28日 2020年09月30日 3.6 3.6.16 2015年12月22 ...