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. 8.5 CheckRemoteDebuggerPresent

    CheckRemoteDebuggerPresent 也是一个微软提供的反调试函数,该函数可以在本地或者远程进程中使用.函数接收两个参数进程句柄和一个指向布尔值的指针.如果指定的进程正在被调试,则函数 ...

  2. 从零搭建Vue3 + Typescript + Pinia + Vite + Tailwind CSS + Element Plus开发脚手架

    项目代码以上传至码云,项目地址:https://gitee.com/breezefaith/vue-ts-scaffold 目录 前言 脚手架技术栈简介 vue3 TypeScript Pinia T ...

  3. 【预定义】C语言预定义代码(宏、条件编译等)内容介绍【最全的保姆级别教程】

    浅谈C语言预定义中的预定义符号,#define,以及符号#,##的相关运用 求个赞求个赞求个赞求个赞 谢谢 先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一 ...

  4. 【C语言深度解剖】复数运算问题--【好题系列】学会这题,结构体没问题

    复数问题 今天博主给大家带来一道博主自己在学校做到的一个题目.这个题目可以很好的加深我们对C语言结构体的理解,在这里分享给大家.学懂这题,我们的C语言结构体,没问题了! 本篇建议收藏后食用!以免退出找 ...

  5. .NET 云原生架构师训练营(模块二 基础巩固 Host)--学习笔记

    2.2.4 核心模块--Host 什么是 Host Host 的默认配置做了哪些事情 框架提供的服务 HostedService 后台服务 ASP.NET Core Web 主机:https://do ...

  6. [Java]Map接口有关总结

    Map接口 1.HashMap和Hashtable的区别 线程安全方面.HashMap是非线程安全的,Hashtable是线程安全的.因为Hashtable内部方法基本都经过synchronized修 ...

  7. vue-element-admin iframes 组件 保留 iframe 操作状态

    由于没有时间去维护这个功能,这个仓库我暂停了,当前博客内容和代码只作为实现思路参考 代码贴前面,gitee地址:https://gitee.com/chkhk/vue-element-admin 可以 ...

  8. P9801 [NERC2018] King Kog’s Reception

    题目传送门 前置知识 线段树 解法 第一眼感觉和 luogu P1083 [NOIP2012 提高组] 借教室 很像.本题同样采用线段树维护,\(sum_{l,r}(1 \le l \le r \le ...

  9. 编写高效的代码,你应该了解Array、Memory、ReadOnlySequence

    针对"缓冲区"编程是一个非常注重"性能"的地方,我们应该尽可能地避免武断地创建字节数组来存储读取的内容,这样不但会导致大量的字节拷贝,临时创建的字节数组还会带来 ...

  10. NC24623 Tree Decoration

    题目链接 题目 题目描述 Farmer John is decorating his Spring Equinox Tree (like a Christmas tree but popular ab ...