新建一个wpf项目,我选择的框架是.net core3.1,目录文件很少,其中MainWindow.xaml就是wpf项目的主窗体文件。

XAML

在wpf里面,用一种标签语言XAML来写UI控件,和HTML一样,XAML是由XML演变而来的。
默认XAML如下

  1. <Window x:Class="WpfApp1.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:WpfApp1"
  7. mc:Ignorable="d"
  8. Title="MainWindow" Height="450" Width="800">
  9. <Grid>
  10. </Grid>
  11. </Window>

window标签里面保函grid标签,这两个标签是两个对象。标签对象之间的关系要么是并排,要么是包含。
在window标签上面设置了很多属性,可以说是Attribute。
而Title,Height,Width是属于这个标签类对象的Property属性。

xaml标签的一部分attribute与C#的标签类的property属性对应。

标签对应C#类

XAML是一种专门用于绘制UI的语言,借助它可以把UI定义与运行逻辑分离开来。XAML使用标签来定义UI元素。
每个标签对应Framework 类库中的一个控件类。通过设置标签的Attribute,不但可以对标签所对应控件类对象的Property进行赋值,还可以做一些额外的事件(如声明名称空间、指定类名等)。

xmlns

XAML语言是从XML语言派生出来的。XML语言有一个功能,就是可以在XML文档的标签上使用xmlns特征来定义名称空间(Namespace),xmIns 也就是XML-Namespace 的缩写了。定义名称空间的好处就是,当来源不同的类重名时,可以使用名称空间加以区分。xmIns特征的语法格式如下:

xmlns[:可选的映射前缀]=”名称空间”

xmIns后可以跟一个可选的映射前缀,就是别名,之间用冒号分隔。如果没有写可选映射前缀,那就意味着所有来自于这个名称空间的标签前都不用加前缀,这个没有映射前缀的名称空间称为“默认名称
空间”——默认名称空间只能有一个,而且应该选择其中元素被使用最频繁的名称空间作为默认名称空间。

上面的例子中,都来自由第二行声明的默认名称空间。

而第一行中的Class特征则来自于第三行中x:前缀对应的名称空间。

这里可以做一个有趣的小实验,如果给第二行声明的名称空间加上一个前缀,比如n,那么代码就必须改成这样才能编译通过:

  1. <n:Window x:Class="WpfApp1.MainWindow"
  2. xmlns:n="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:WpfApp1"
  7. mc:Ignorable="d"
  8. Title="MainWindow" Height="450" Width="800">
  9. <n:Grid>
  10. </n:Grid>
  11. </n:Window>

xaml引用名称空间就自己写一个,xmlns,冒号后面跟一个自己取得名字,然后等于,vs会自动提醒你的
image.png
这些看起来的url的地址的名称空间,是硬编码的,不是url,用这个像url的地址,编译器会自动编译。
前面两个默认引进来的默认名称空间很重要,presentation包含绘制UI相关的程序集,xaml包含解析xaml语言解析处理。

引用自己的程序集

在等一个解决方案里面有多个项目,先在依赖项里面引用对应的类库。
在XAML里面引用自己写的类库的话
语法如下

  1. xmlns:映射名="clr-namespace:类库中名称空间的名字;assembly=类库文件名"

如果要使用的QWE类库,编译后就是QWE.dll,在这里面有两个名称空间,ABC和FGH。就写成下面这样了
映射名随意,可以建议和名称空间一样,方便区分

  1. xmlns:abc="clr-namespace:ABC;assembly=QWE"
  2. xmlns:fgh="clr-namespace:FGH;assembly=QWE"

接下来就可以使用这里面的类对象了,就和其他标签一样的用法。

x:Class

这说明,x:Class 这个Attribute 的作用是当XAML解析器将包含它的标签解析成C#类后,这个类的类名是什么。
上面x:Class="WpfApp1.MainWindow"里面WpfApp1是名称空间,MainWindow就是这个Window标签生成的C#类的类名,自带啊,下面的这个MainWindowA是因为我把x:Class改成这样的。

这个关于窗体的C#类,继承于Window类。你会发现他是partial部分类,下面这一部分是项目自带的,写逻辑用的部分,还有部分呢?就是窗体里面的元素编译成C#后的一部分。和winform不一样,wpf看不到那部分。

说白了,就是把复杂繁琐的UI部分分离出来,写代码的不要管这部分怎么实现的,只要知道,用正确的XAML,系统会自动编译好。你专心写逻辑就行

  1. namespace WpfApp1
  2. {
  3. /// <summary>
  4. /// Interaction logic for MainWindow.xaml
  5. /// </summary>
  6. public partial class MainWindowA : Window
  7. {
  8. public MainWindowA()
  9. {
  10. InitializeComponent();
  11. }
  12. }
  13. }

XAML为对象属性赋值

需要设置标签的值的时候,不知道怎么搞,就光标移动上去,F1,看官方文档。
官方有介绍属性怎么赋值,赋值些什么,甚至属性元素怎么赋值。

使用字符串进行简单赋值

Rectangle元素的这些Height,Margin,Fill等这些,在这里都是简单赋值,就是写个特定的字符串,编译以会给你解析。

  1. <Window x:Class="WpfApp1.MainWindowA"
  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:WpfApp1"
  7. mc:Ignorable="d"
  8. Title="MainWindow" Height="450" Width="800">
  9. <Grid>
  10. <Rectangle HorizontalAlignment="Left" Height="100" Margin="307,180,0,0" Stroke="Black" VerticalAlignment="Top" Width="100" Fill="red"/>
  11. </Grid>
  12. </Window>

image.png

使用属性元素进行复杂赋值

上面的简单赋值挺好的,但是有时候需要复杂的属性值,就写属性元素,把属性当做当前标签的子标签。
系统会有提示。
image.png
有些属性不能用属性元素赋值,比如Height,Width等,也没有必要吧,简单赋值多简单。但是比如Fill这种颜色的属性,可能有渐变色,渐变方向,透明度等复杂参数,这种麻烦的属性可以用属性元素
在Fiil属性标签里面,还可以写其他的子标签。能写子标签的系统都有提示,没有提示说明可能真的不适合或者不能搞属性元素赋值呢。
image.png
最终写出来的属性元素就是这样的
image.pngimage.png

建议

  • 能使用Attribute=Value形式赋值的就不使用属性元素。
  • 充分利用默认值,去除冗余: StartPoint=”0,0” EndPoint=”1,1”是默认值,可以省略
  • 充分利用XAML的简写

    标记拓展

    需要给一个属性赋值多个值的时候,就用这种{}花括号。
    这里的例子是Text=”{Binding ElementName=abc,Path=Value}”

  • 当编译器看到这句代码时就会把花括号里的内容解析成相应的对象。

  • 对象的数据类型名是紧邻左花括号的字符串,这里是Binding。
  • 对象的属性由一串以逗号连接的子字符串负责初始化(注意,属性值不再加引号)。 ```xml
  1. 还可以写成这样的属性元素
  2. ```xml
  3. <Window x:Class="WpfApp1.MainWindowA"
  4. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  5. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  6. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  7. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  8. xmlns:local="clr-namespace:WpfApp1"
  9. mc:Ignorable="d"
  10. Title="MainWindow" Height="450" Width="800">
  11. <Grid>
  12. <TextBox Width="100" Height="20">
  13. <Binding ElementName="abc" Path="Value"></Binding>
  14. </TextBox>
  15. </Grid>
  16. </Window>

这种写法就类似于C#的创建一个对象且默认初始化(这里是测试,不是真实情况)

  1. Binding binding = new Binging()
  2. {
  3. ElementName="abc",
  4. Path="Value"
  5. }

事件

标签的属性里面有些和对应的标签类对象的属性对应,有些标签属性是事件,这种闪电符号的就是事件,click点击事件,就是点击这个button会执行这个事件。和winform一样。这样的属性绑定事件和前端的vue绑定事件一样。
image.png
可以新建一个事件,名字是默认的,建好后可以改
image.png
右键转到定义,或者F12。
就会在后置代码里面新建一个事件方法,类似winform。
image.png
当然也可以直接给Click赋值一个自定义的名字,然后右键转到定义,也能自动创建好这样的一个事件方法。