WPF编程基础入门 ——— 第二章 XAML

XAML 简述

XAML(eXtensible Application Markup Language,可扩展应用程序标记语言)是微软公司创建的一种新的描述性语言,用于搭建应用程序用户界面。XAML实现了用户界面与业务逻辑完全分离。XAML是一种解析性的语言,尽管它也可以被编译。它的优点是简化编程式上的用户创建过程,应用时要添加代码和配置等。
在第1章中,对照了HTMLXAML两者的异同点。发现尽管XAML在元素的声明、程序样式的设置等语法结构上和HTML上有相似之处,但XAML有别于HTML最显著的特征是xmlns指令和标记扩展。其中,xmlns指令需要在标记中关联名称空间。
XAML并不是HTML,而是基于XML的,是WPF的外在表现形式。而HTML只是一种标记语言,仅仅是用来为浏览器呈现页面内容。XAML可以用来呈现信息和请求用户输人等基本的功能,它还支持动画和3D等高级特性。
XAML是可扩展的,开发人员可以创建自定义的控件、元素和函数来扩展XAML。由于XAML各元素在本质上就是WPF类的映射,因此开发人员可以很轻松地使用面向对象的技术对XAML元素进行扩展。也就是说,可以开发一些自定义控件和组合元素,用户界面设计人员和开发人员直接使用即可,软件真正做到了可复用性。
XAML的发音为"Zamel"。虽然XAML包含了许多新规则、元素和语法,但我们并不认为学习它是一个麻烦的过程。只要读者稍微具备一些HTML基础知识,就可以快速地掌握XAML中的大部分内容。


XAML 文档框架

创建一个新的WPF项目 WpfApp2

如何创建项目 参见之前的文章:
WPF编程基础———第一章 引言 创建一个WPF项目.

所生成的基本项目结构
我们目前分析的XAML为MainWindow.xaml,后台的cs代码等等之后都会渐渐提到

系统自动生成的代码如下:
VS2019版本自动生成的代码之中有更多默认xmlns指令

<Window x:Class="WpfApp2.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:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        
    </Grid>
</Window>

在此首先了解XAML文件基本框架,这个文档包含一个顶级元素Window和一个Grid元素。Window代表整个窗口,Grid布局上可以放置所需控件。一个XAML文件只能有一个顶级元素。
WPF中可以当顶级元素的还有Page元素和Application元素。
Page用于可导航的应用程序; Application用于定义应用程序的资源和启动设置。
分析Window开始标签,依照自上而下的顺序,它包含一个类名、五个xmlns指令关联的名称空间,三个属性(Title、Height、Width)以及一个有关于兼容性mc名称空间的指令。

XAML 文档结构

在XAML文件基本框架上,为此程序添加设计要求:在Button上放置一个Image和一个TextBox。在<Grid></Grid>之间,添加XAML代码来实现设计要求。
XAML注释方式 :<!-- -->

<!-- window 代码部分省略 -->
    <Grid>
        <Button Width="600" Height="400">
            <Button.Content>
                <!-- 设置为垂直方向 -->
                <StackPanel Orientation="Vertical">
                    <Image Source="battle.jpg" Width="600" Height="375"></Image>
                    <TextBox Text="Hathaways Flash" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBox>
                </StackPanel>
            </Button.Content>
        </Button>
    </Grid>
</Window>

效果图
在这里插入图片描述
根据运行之后的效果图和分析代码的逻辑结构我们可以知道,Window为顶级元素,在Grid布局下有一个Button,在Button下使用StackPanel布局后加入一个Image和TextBox。
此XAML文档树形结构

window
Grid
Button
StackPanel
Image
TextBox

应用程序的UI在用户看来是平面结构的,与传统设计结构不同的是,在后台开发者面对的XAML是树形逻辑结构的,不过Button上放置其他控件的方式有很多,但文档框架始终都是树形结构。

XAML 基础语法

XAML中最基本的语法元素与XML类似,下面回顾一下XML中的标签、属性和内容的语法。

标签

标签通常是以<>开始,以</>结束的,一一个标签的声明通常表示一个对象。 如<Window></Window><Grid></Grid>分别定义了一个窗体对象及一个Grid对象,标签定义有以下两种常用写法。
(1)非自闭合标签:如<Window></Window><Grid></Grid>,标签要成对出现。
(2)自闭合标签:如<Window /><Grid/><Button/>
这种自闭合标签用于无内容情况下,可以让代码看上去更简洁,当然,正常情况下WindowGrid都是有内容的。

属性

属性通常以键值对形式出现,形式如下。
Attribute = Value
例如,<Window></Window>标签中的"Title=“MainWindow” Height=“450” Width=“800” ",等号左边表示Window标签的属性,等号右边表示该属性的值。

内容

一组标签对之间夹杂的文本或其他标签都称为这个标签之间的内容。此处Window标签的内容就是一对<Grid></Grid>标签。


XAML 中的属性

继续使用WpfApp2这个解决方案,根据需要还会不断丰富其功能,以便配合学习讲解XAML

XAML 简单属性

XAML是声明性语言,XAML编译器给每个标签创建一个与标签对应的对象,再对其属性初始化。所以,每个标签是要先声明对象,再为对象赋初值。赋值方法有两种:一种是XAML中的字符串简单赋值,另外一种是在后台CS代码中,使用属性元素进行复杂赋值。

1.字符串简单赋值

XAML使用标签定义UI元素,每一个标签对应。NET Framework类库的一个 控件类。通过设置标签的Attribute(属性),实现标签对应的控件对象Property(属性)赋值。
首先在WpfApp2新建一个新的WPF项目:
在这里插入图片描述在这里插入图片描述其中Grid标签之间的代码

    <Grid>
        <!-- 设置名称属性为rectangle 颜色为Blue 边界为左50,上75,右125,下175 -->
        <Rectangle x:Name="rectangle" Fill="Blue" Margin="50,75,125,175"></Rectangle>
    </Grid>

效果图
在这里插入图片描述其中在VS2019切换启动项目在菜单栏下方
在这里插入图片描述

2.属性元素复杂赋值

在CS代码中,创建对象,并设置他们的属性,代码如下:

/*using System... 省略*/
namespace Rectangle
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            SolidColorBrush scb = new SolidColorBrush();
            scb.Color = Colors.Yellow;
            this.rectangle.Fill = scb;
        }
    }
}

效果图
在这里插入图片描述两种赋值方法相对照,这里需解释Fill属性的用法。因为Fill类型是Brush,但是Brush一个抽象类,由于抽象类不能实例化.所以只能用抽象类的子类实例赋值,Brush的派生类简要说明如下。

  • SolidColorBrush:使用纯Color绘制区域;
  • LinearGradientBrush:使用线性渐变绘制区城;
  • RadialGradientBrush:使用径向渐变绘制区域;
  • ImageBrush:使用图像(由ImageSource对象表示)绘制区域:
  • DrawingBrush:使用Drawing绘制区域。绘图可能包含向量和位图对象:
  • VisualBrush:使用Visual对象绘制区域,使用VisualBrush可以将内容从应用程序的一个部分复制到另一个区域,这在创建反射效果和放大局部屏幕时会非常有用。

XAML 复杂属性

在WpfApp2中加入新的设计需求: Grid的背景使用渐变色,渐变方案是:由红色到黄色,再由黄色到绿色。要实现该功能就需要对Grid.Background中的LinearGradientBrush进行设置,代码如下。

<Grid>
        <Grid.Background>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="Red" Offset="0"/>
                <GradientStop Color="Yellow" Offset="0.6"/>
                <GradientStop Color="Green" Offset="1"/>
            </LinearGradientBrush>
        </Grid.Background>
        <!-- 保留原Button后续代码 -->

效果图
在这里插入图片描述根据如上所示的效果,其中代码中的Grid.Background便是复杂属性。下面介绍程序中用到的属性。
现在我们知道LinearfGradientBrush的功能是线性渐变笔刷,填充线性渐变颜色到当前区域,故可搭配两种或两种以上的颜色。
它的的重要属性有GradientStop(倾斜点)、Color(渐变颜色)、Offset(偏移量)、StartPoint(起点坐标)、EndPoint(终点坐标)。
LinearGndientBrush的渐变色是由多个GradientStop组成的,其中的ColorOffset分别表示渐变色值和颜色起始位置,Offset宽度是整个绘制区域,取值范围为0~1.0。

XAML 附加属性

继续在WpfApp2中加入新的设计需求,在Grid布局中加入一个蓝色矩形与之前的button并列

效果图如下
在这里插入图片描述
要实现如上的效果,首先我们需要对Grid布局中新增加一列,对<Grid.ColumnDefinitions>属性设置代码如下:

<!-- 保留之前的代码 -->
        </Grid.Background>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

要将<Rectangle>置于<Grid>的第1列,类似程序语言中的数组,Grid布局的起始行与列都是从0开始,

<!-- 保留之前的代码 -->
        </Button>
        <Rectangle x:Name="Rec" Grid.Column="1" Fill="Blue" Margin="25"></Rectangle>
    </Grid>
</Window>

此例之中用的属性,<Grid.ColumnDefinitions>是复杂属性,Grid.Column="1"位于<Rectangle>内部,这就是附加属性。
这时候出现了一个疑问,以上两个属性均为Grid.的形式,但却是不同的属性,因为Grid.ColumnDefinitions这一属性隶属于Grid,他完全可以视为Grid的子标签,而Grid.Column="1"是在<Rectangle>内部,用来设置Rectangle标签的。他并非真正的属性,被转为调用Get.SetColumn() 方法来实现,之后会发现附件属性全部在控件布局之中。

XAML 处理特殊字符和空白

在XAML中,可以让一些特殊字符作为元素的内容出现,例如,之前Button中的Hathaways Flash要变成<Hathaways Flash>显示,需要修改TextBox标签中的Text="&lt;Hathaways Flash&gt;"

XAML中特殊字符处理方式
特殊字符处理方式特殊字符处理方式
<&lt;&&amp;
>&gt;"&auot;

在XAML中处理特殊字符并不难,但还存在一个关键问题——空白的处理。
在默认情况下,XAML忽略所有的空白,这就意味着空格、Tab键、硬回车、带有多个空格的长字符串被转换为单个空格。有时放在文本中的空格,希望输出,例如,文本框中输出带尖括号及空格的字符,如< Hathaways Flash >,则需要修改代码如下,

<TextBox Text="&lt; Hathaways Flash &gt;" xml:space="preserve" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBox>

在保留空格的元素(TextBox)中使用" xml:spac= “preserve””, Text属性中的空格被保留输出。事实上" xml:spac= “preserve”"特性是XML标准的一部分。


XAML 名称空间

我们来继续学习并介绍XAML文件根标记中的两个默认XAML名称空间映射及其用意,同时还将说明如何生成类似的映射,便于用在代码中或单独的程序集中定义的元素。

XAML 名称空间的作用

开发语言会将常用功能以类的形式封装,开发人员根据业务需求,也会封装符合自身业务需求的类,有序组织这些类。这样,一方面,便于开发人员准确调用;另一方面,编译器可以有效地识别具有相同命名的类,就引入了名称空间。
名称空间是通过类似树形结构来组织各种类,是一种较为有效的类名排列方式。
XAML和.NET其他语言一样,也是通过名称空间有效地组织XAML内部的相关元素类,但是XAML的名称空间与. NET中的名称空间不是一对一的映射关系 ,而是一对多映射。

XAML 默认名称空间

在之前我们建立的WPF项目的XAML文档结构之中,了解到系统默认的名称空间的代码如下,

<Window x:Class="WpfApp2.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:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="1300">

XAML名称空间是XML名称空间概念的扩展。xmlns是XML-Namespace的缩写,看起来类似“网址”,但在浏览器中无法打开,所以它并不是网址。它是遵循XAML解析器标准的命名规则,是声明程序集和.NET名称空间的引用。

  • 其中,“xmlns=“http://schemas.microsoft.com/winfx/2006/xaml/presentation”"与.NET的名称空间中的System.Windows下的类相对应,包含XAML基本的布局和控件。
  • 带x的“xmlns:x=“http://schemas.microsoft.com/winfx/2006/xaml”"对应一些XAML语法和编译相关的CLR名称空间。
  • 带d的“xmlns:d="http://schemas.microsoft.com/expression/blend/2008""是让我们在写xaml文件时看到控件的大小。
  • 带mc的“xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006""关于程序兼容性的控制
  • 带loacl的“xmlns:local=“clr-namespace:WpfApp2””对应本地项目的名称空间
  • mc:Ignorable="d"的意思就是告诉编辑器(VS2019)在项目运行时忽略命名空间d设置的大小

为了避免概念上的混淆,在此,对C#、CLR与.NET简要说明一下。在人们做开发时,常会使用C#语言,它是. NET的核心开发语言; . NET(.NET Framework)是一个运行时平台;CLR(Common Language Runtime)是公共语言运行库,与Java虚拟机(JVM)一样是一个运行时环境,它负责资源管理(内存分配和垃圾收集等),确保应用和底层操作系统之间必要的分离。正是因为有了CLR,所以.NET成为一个跨语言的集成开发平台。

XAML 名称空间的标记扩展

标记扩展是XAML的重要特性,它放在一对花括号{}中,使用类似对象标签的方式来精确解析。
现在增加新的设计需求:设置矩形框的颜色为紫色。简单的方法是Fill= “Violet” ,但是我们现在用标记扩展来实现。先设置窗体资源,代码如下。

<!--保留Window代码-->
    <Window.Resources>
        <SolidColorBrush x:Key="bg" Color="Violet"    />
    </Window.Resources>
    <Grid>
<!--保留后续代码-->

再修改Rectangle的Fill,代码如下。

<Rectangle x:Name="Rec" Grid.Column="1" Fill ="{StaticResource bg}" Margin="25"></Rectangle>

运行代码后,效果图如下。Fill使用标记扩展来赋值。
在这里插入图片描述

XAML 内置 XAML特性名称空间指令及含义

XAML 名称空间指令含 义示 例
x:Array创建CLR数组< x;ArrayType= “(x:Type Button)”>
< Button/>
< Button/>
</x:Array >
x:Class定义的类名< Window
x:Class =”MainWindow">…
</ Window >
x:ClassModifier定义类型的模式Public、Internal< Window…
x:Class = " MainWindow">…
x:ClassModifier = " Pubie"…
</ Window >
x:CodeXAML中内嵌代码< x:Code >
Public void SomeMethod(){}
</x:Code >
x:Key包含在字典中的元素键< Window. Resources >
< SolidColorBrush x: Key = “bg”…/>
</Window. Resources >
x:Name指定元素的编程名< Rectangle x:Name= “Rec” …/>
x:Null创建一个空值< TextBox Text= "{x:Null} ">
x:Static静态字段和属性值< Button background = “{Statie…)”/>
x:Type提供CLR类型< ControlTemplate >
TargetType= "{x:Type Button} "
< /ControlTemplate >
x:TypeArguments为实例化泛型类型指定泛型类型的参数< object x: Class = " namespace. classname"
x:TypeArguments="{x; Type type1}
[,{x: Type type2},{x:Type type3… }]">< /object>
x:XDataXAML指令元素主要用作 XmlDataProvider 的子对象
或 XmIDataProvider.XmlSerializer属性的子对象

XAML 类型转换器

XAML的属性元素赋值形式为。Attribute = Value此处的Value是一个String类型但在后台CS代码中,对象的属性(Property)类型不一定是String类型。为了解决XAML与CS代码中的数据类型不统一,使用TypeConverter类。这个类的功能是:将值类型转换为其他类型,如可以把字符串转换成对象。

  • 现在在WpfApp2中新增需求,在CS中创建Teacher类,Teacher中有Name和Student两个属性,其中Name类型是String,Student类型是Teacher;XAML中的Button按下后弹出一个消息框,消息框中的显示内容为“I AM THE FLASH”。其中,消息框调用方式为Teacher.Student.Name

首先是在后台CS代码中创建Teacher类,
在这里插入图片描述变更XAML中的代码如下:

<!--保留Window代码-->
    <Window.Resources>
        <local:Teacher x:Key="teacher" Student="I AM THE FLASH"/>
        <SolidColorBrush x:Key="bg" Color="Violet" />
    </Window.Resources>
<!--保留Window代码-->
        <Button Name="Btn" Width="600" Height="400" Click="Btn_Click">
<!--保留Window代码-->

在给Button加入Click后在MainWindow.xaml.cs之中的Btn_Click方法中编辑事件代码

        private void Btn_Click(object sender, RoutedEventArgs e)
        {
            Teacher t = (Teacher)this.FindResource("teacher");
            MessageBox.Show(t.Student.Name);
        }

这时候运行代码点击按钮报错

错误XDG0028	“Teacher”的 TypeConverter 不支持从字符串进行转换。

而这个问题的解决方案是通过TypeConverter派生用户自定义类,重载该类的ConvertForm方法。该方法中有一个Value,他是在XAML中进行设置的,再把这个Value转成用户期望的数据类型。下面创建一个将String转换成Teacher的用户自定义类,将这个类命名为StringToTeacherTypeConverter

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel; // ADD new NameSpace

namespace WpfApp2
{
    class StringToTeacherTypeConverter:TypeConverter
    {
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is string)
            {
                Teacher t = new Teacher();
                t.Name = value as string;
                return t;
            }
            return base.ConvertFrom(context, culture, value);
        }
    }
}

之后修改Teacher.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;

namespace WpfApp2
{
    [TypeConverterAttribute(typeof(StringToTeacherTypeConverter))]
    public class Teacher
    {
        public string Name{ get; set; }
        public Teacher Student { get; set; }
    }
}

现在运行代码,单击Button,弹出消息框,效果图如下
在这里插入图片描述此处可以把TypeConverterAttribute中的Attribute省去,因为特征类在使用时可省略Attribute


XAML 导入程序集

在项目开发时,一个项目由多个模块构成,模块之间可以相互调用。在用VisualStudio2019创建的解决方案下,每个项目都可以独立编译,独立编译的结果就得到一个程序集。常见的程序集包括exe(可执行文件)和dII(Dynamic Link Library动态链接库)。这里说的“导入程序集”是指dll类型。程序集要放在合适的名称空间下,名称空间解决不同模块类名相同问题。
在XAML中导人程序集。设用户自定义的程序集名为UserLibrary.dlI,它有CommCont两个名称空间,在XAML中引用这两个名称空间的语法格式如下。

xmlns:映射名= "clr - namespace:名称空间;assembly=程序集名"

接下来根据语法格式,在程序集UserLibrary.dll中的两个名称空间对应的XAML引用为:

xmlns:cont= "clr - namespace :Comm; assembly = UserLibrary"
xmlns:cont= "clr - namespace :Cont; assembly = UserLibrary"

在XAML文档添加引用后,就可以使用名称空间中的类,语法格式如下。

<映射名:类名>...</映射名:类名>
<comm:类名></comm:类名>
<cont:类名></cont:类名>

这个例子只是简单引入,后面会详细说明。


本章小结

本章节从XAML文档框架开始,让我们认识到UI的平面结构对应着XAML文档的树形结构。XAML是可扩展的应用程序声明式语言,它是基于XML的,所以XAML中的标签、属性、内容语法结构与XML有相似之处。我们所写的案例从Button上放置Image、TextBox的例子开始,通过分层叠加式案例,逐步地讲解XAML的复杂属性、附加属性、xmIns指令和名称空间中的标记扩展,并使用TypeConverter类把字符串转换成对象。还讲解了项目开发时,在XAML导入程序集的语法。倘若在学习中,有些内容不懂,可以跳过,当遇到具体应用后,回过头来阅读,会恍然大悟。对XAML语法知识有所了解以后,便可以用它来创建用户界面了。


相关阅读
上一篇:WPF编程基础入门 ——— 第一章 引言.
下一篇:WPF编程基础入门 ——— 第三章 布局(一)布局原则.
WPF编程基础入门 ——— 目录导航.

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

W.Lionel.Esaka

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值