新建一个wpf项目,我选择的框架是.net core3.1,目录文件很少,其中MainWindow.xaml
就是wpf项目的主窗体文件。
XAML
在wpf里面,用一种标签语言XAML来写UI控件,和HTML一样,XAML是由XML演变而来的。
默认XAML如下
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</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,那么代码就必须改成这样才能编译通过:
<n:Window x:Class="WpfApp1.MainWindow"
xmlns:n="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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<n:Grid>
</n:Grid>
</n:Window>
xaml引用名称空间就自己写一个,xmlns,冒号后面跟一个自己取得名字,然后等于,vs会自动提醒你的
这些看起来的url的地址的名称空间,是硬编码的,不是url,用这个像url的地址,编译器会自动编译。
前面两个默认引进来的默认名称空间很重要,presentation
包含绘制UI相关的程序集,xaml
包含解析xaml语言解析处理。
引用自己的程序集
在等一个解决方案里面有多个项目,先在依赖项里面引用对应的类库。
在XAML里面引用自己写的类库的话
语法如下
xmlns:映射名="clr-namespace:类库中名称空间的名字;assembly=类库文件名"
如果要使用的QWE类库,编译后就是QWE.dll,在这里面有两个名称空间,ABC和FGH。就写成下面这样了
映射名随意,可以建议和名称空间一样,方便区分
xmlns:abc="clr-namespace:ABC;assembly=QWE"
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,系统会自动编译好。你专心写逻辑就行
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindowA : Window
{
public MainWindowA()
{
InitializeComponent();
}
}
}
XAML为对象属性赋值
需要设置标签的值的时候,不知道怎么搞,就光标移动上去,F1,看官方文档。
官方有介绍属性怎么赋值,赋值些什么,甚至属性元素怎么赋值。
使用字符串进行简单赋值
Rectangle元素的这些Height,Margin,Fill等这些,在这里都是简单赋值,就是写个特定的字符串,编译以会给你解析。
<Window x:Class="WpfApp1.MainWindowA"
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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Rectangle HorizontalAlignment="Left" Height="100" Margin="307,180,0,0" Stroke="Black" VerticalAlignment="Top" Width="100" Fill="red"/>
</Grid>
</Window>
使用属性元素进行复杂赋值
上面的简单赋值挺好的,但是有时候需要复杂的属性值,就写属性元素,把属性当做当前标签的子标签。
系统会有提示。
有些属性不能用属性元素赋值,比如Height,Width等,也没有必要吧,简单赋值多简单。但是比如Fill这种颜色的属性,可能有渐变色,渐变方向,透明度等复杂参数,这种麻烦的属性可以用属性元素
在Fiil属性标签里面,还可以写其他的子标签。能写子标签的系统都有提示,没有提示说明可能真的不适合或者不能搞属性元素赋值呢。
最终写出来的属性元素就是这样的
建议
- 能使用Attribute=Value形式赋值的就不使用属性元素。
- 充分利用默认值,去除冗余: StartPoint=”0,0” EndPoint=”1,1”是默认值,可以省略
-
标记拓展
需要给一个属性赋值多个值的时候,就用这种{}花括号。
这里的例子是Text=”{Binding ElementName=abc,Path=Value}” 当编译器看到这句代码时就会把花括号里的内容解析成相应的对象。
- 对象的数据类型名是紧邻左花括号的字符串,这里是Binding。
- 对象的属性由一串以逗号连接的子字符串负责初始化(注意,属性值不再加引号)。
```xml
还可以写成这样的属性元素
```xml
<Window x:Class="WpfApp1.MainWindowA"
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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBox Width="100" Height="20">
<Binding ElementName="abc" Path="Value"></Binding>
</TextBox>
</Grid>
</Window>
这种写法就类似于C#的创建一个对象且默认初始化(这里是测试,不是真实情况)
Binding binding = new Binging()
{
ElementName="abc",
Path="Value"
}
事件
标签的属性里面有些和对应的标签类对象的属性对应,有些标签属性是事件,这种闪电符号的就是事件,click点击事件,就是点击这个button会执行这个事件。和winform一样。这样的属性绑定事件和前端的vue绑定事件一样。
可以新建一个事件,名字是默认的,建好后可以改
右键转到定义,或者F12。
就会在后置代码里面新建一个事件方法,类似winform。
当然也可以直接给Click赋值一个自定义的名字,然后右键转到定义,也能自动创建好这样的一个事件方法。