WPF教程一:创建Hello world来理解XAML的内容及编译

在实际的WPF开发中遇到很多再用Winform写法来写WPF的开发人员,很多时候项目进度延期、出现非必要的BUG等等、大多是因为开发人员虽然是在写WPF,但是没有好好的学过WPF,就导致无法发挥出WPF的优势、很多地方都是开个线程处理完成后一个回调UI线程函数里面套一整段代码,这种情况下不仅难处理多线程问题、也会出现很多偶发性的BUG,不好追踪问题在哪里。同时也会因为开发人员对WPF的理解参差不齐导致架构设计和使用过程中代码凌乱。所以今天开始hello world 来梳理WPF。

一、使用XAML创建可以显示hello world的文本框

  经常写winform窗体的同学一定深有感触、拿到UI给的图之后、我们如果想做的比较漂亮。大部分都是通过拖控件、然后把用户界面的后台代码中设置动画效果、大小、位置等等。如果需要适配多种分辨率是更难受的。特别是一些需要深度定制的东西、可能很多开发时间都会用在这里。解决一些稀奇古怪被测试出来的的显示问题。

  而在WPF中提出了XAML的概念、我们可以使用XAML标签来设计和构成我们的用户界面。而XAML丰富的标签一旦正确的使用,则会大大提高我们写出更漂亮的界面的能力。

只写文字大家都会反感。我们通过讲解例子来认识XAML。首先创建一个WPF工程。

1、写下第一行Hello world

打开VS选择创建WPF项目,点击下一步。

img

设置项目名称为Hello World点击创建。就创建了我们第一个WPF项目。

img

通过解决方案标签项我们可以看到整个解决方案的目录结构。而项目中的MainWindow就是我们本次分析的重点。

img

我们这次的重点在MainWindow.xaml和其对应的cs,所以其他部分不是本次的关注重点,也就不讲了。

首先双击MainWindow.xaml,在Grid标签中添加节点。然后在VS中按下F5键。程序就会执行编译,如果成功的话就会跑起来,并且看到我们输入的Hello world!。

<Window x:Class="HelloWorld.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:HelloWorld"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <TextBox Text="Hello world!"/>
    </Grid>
</Window>
img

从我们看到这个显示出来的hello world!的这一刻开始,就正式开始了本章内容的讲解。

二、理解XAML中的文法规范级命名空间

 1 <Window x:Class="HelloWorld.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:HelloWorld"
 7         mc:Ignorable="d"
 8         Title="MainWindow" Height="450" Width="800">
 9     <Grid>
10         <TextBox Text="Hello world!"/>
11     </Grid>
12 </Window>

为了方便理解,我加入了行号,如果想系统的学习XAML可以先学习一下XML,XAML是遵循XML文法规范的,但是对于我们入门来说了解嵌套、 属性的赋值和设置,就可以了。

我们的整体XAML结构大致为

<Window>

  <Grid>

    <TextBox/>

  </Grid>

</Window>

我们当前的XAML根节点是一个Window节点,Window节点代表当前所显示的整个窗口、在Window节点内部有一个Grid节点,Grid节点是一个布局元素里面可以放置的所有的控件、Grid节点包含了一个内部的TextBox节点,而这个TextBox就是我们所说的控件,而我们看到的显示的内容是在Text=“”内赋值的。对于XAML中的内容。可以理解为把后台的.cs代码文件通过xaml可视化的方式进行设置,如果有不知道含义的地方,可以用鼠标点在对应的节点上然后按F12就可以跳转到对应的定义中。

img

比如我们把光标点在Grid上。按下F12。就会跳转到下图的位置。原来Grid继承自一个Panel。里面包含了Column、Row等等。我们就知道了。Grid是一个拥有横、列的网格面板。

img

而在TextBox上按F12之后,就会看到这是一个控件、显示或编辑文本的。

其他的元素同样的道理。把鼠标放置在对应的元素节点上按下F12就会显示对应的内容。

img

接下来我们来看命名空间。

名称空间看上去好像是一个URI的WEB位置,但实际上不是,URI格式的命名空间,不同组织就基本不会使用相同的名称空间创建不同的基于XAML的语言。

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
是WPF核心名称空间。 它包含了所有WPF类,包括创建界面的控件。 该名称空间没有使用前缀、所以它成为整个文档的默认命名空间。也就是说除非指明了名称空间,否则每个元素都直接使用这个名称空间。 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

是XAML名称空间,它包含各种XAML的特性,该命名空间被映射为前缀x。可以在元素名称之前放置x 来使用该名称空间。例如x:Name,x:Class=”HelloWorld.MainWindow”。

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

是旨在提供设计师支持,该名称空间使XAML元素上的这些属性仅影响XAML行为的设计方面。 而在运行过程中会忽略掉这些属性。比如d😀esignHeight=”100″ d😀esignWidth=”100″,这个在设计时看不到该控件时,在对应的控件上添加此属性特别有效。 在Blend下使用比较多的是针对集合的d😀ataContext、d😀esignData。等等。感兴趣的可以看看Blend相关的。

xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006″ 标识使运行时XAML解析器能够忽略设计属性,比如mc:Ignorable:d。d前缀的在运行时XAML解析器解析时就会忽略了。 xmlns:local=”clr-namespace:HelloWorld” 这个就是我们工程自己的名称空间了。

三、理解XAML中的的属性和事件

 XAML中的属性:

我们通过前面的讲解了通过跳转查看XAML节点的含义,比如<Grid>是布局用的Panel。<TextBox/>是显示和编辑无格式文本的。
那么现在我们来理解属性。
在元素中我们通过跳转了解到了XAML节点都是一个一个的类对象。里面定义了属性、方法及事件。那么在XAML中,我们可以在这里设置属性、事件。通过设置这些来修改样式及监听对应的事件消息。
那么在属性中分为简单属性和复杂属性。我们在Textbox上按F12跳转过去,然后我们找个属性来演示一下简单属性和复杂属性如何使用。
img

在Foreground上我们看到了该属性是一个Brush类型。而在WPF中Brush支持纯色、线性渐变色等等。我们设置代码如下。

img

这样我们就在第一个TextBox 上设置了背景色为一个枚举值。用于表示一个颜色值。 而当我们想设置复杂Brush的时候,我们就可以使用复杂属性,第二个TextBox通过属性的嵌套来创建一个复杂的线性画刷。2个TextBox显示效果如下:

img

但是新的问题又来了,现在大部分主流的App都支持更换皮肤,明暗主题什么的。而我们只能通过硬编码的形式设置属性,那岂不是要实现更换皮肤,每个控件都要设置一遍?

有没有什么办法能让XAML属性绑定一个变量,而我们去修改这个变量?

实现方法的办法之一就是使用扩展标记:假设我们的内容都放在一个windows里做演示:

img

添加window的资源。同时使用DynamicResource来绑定资源。就可以实现。一个资源修改,所有使用的地方都跟着变化。后面会详细讲到。如何使用扩展标记来进行主题切换。

而在WPF中提出的是依赖项属性的概念。这个和路由事件需要花费精力好好学一下。才能更好的使用和理解WPF。

XAML中的事件:

为了增强事件的传播能力,WPF中提出了路由事件的概念,路由事件可以在元素树中向上和向下传播,并且沿着传播路径被事件处理程序消费。我们在XAML中添加2个处理按下和抬起事件的代码。

img

后台的处理代码。

img

路由事件和依赖项属性这些主要会放在MVVM中讲。这里主要了解一下。XAML下如何创建事件处理程序。

四、从生成过程日志查看XAML的编译。

对于加载和编译XAML,有四种方式:

1、只使用代码来创建XAML对应的元素,类似于winform的写法;

2、使用代码和未经编译的XAML。

3、使用代码和编译过的XAML。

4、只使用XAML。

这里我们只去理解一个使用代码和编译过的XAML。其他的工作到目前未知,觉得用到的比较少,等真正用到了。只要理解了可以在去查如何使用。

当我们编译WPF程序时,编译过程分为了2个阶段,第一个个阶段是将XAML文件编译为BAML文件。我们使用的C#语言,所以会在临时文件生成对应的.g.cs文件

g代表generated。

当从XAML到BAML的编译结束后,编译器会编译代码和生成的部分类文件。编译过的代码会变成单个程序集。每个窗口的BAML都会作为独立资源被嵌入到程序集中。

我们通过修改VS的设置来查看编译过程。

在VS选择工具=>选项=>项目和解决方案=>生成并运行=>MSBuild项目生成输出详细程序=>设置为详细。而后点击编译。我们来观察输出的内容。

img

我们查看关键的几处

img
img
img
img
img

以上截图就是完整的编译过程。

我创建了一个C#相关的交流群。用于分享学习资料和讨论问题。欢迎有兴趣的小伙伴:QQ群:542633085

技术交流Q群: 1012481075 群内有各种流行书籍资料
原文链接:https://www.cnblogs.com/duwenlong/p/14424000.html

发表评论

您的电子邮箱地址不会被公开。

WeChat
WeChat
QQ
QQ
返回顶部