WPF 界面应用开发框架

First Post:

Last Update:

WPF 与 Winform

WPF 与 Winform 都是 windows 的界面应用开发框架
不过 WPF 较新, Winform 较旧

Winform 采用 C# 语言直接描述界面
WPF 则是使用 .xaml 文件描述界面, 像素无关

了解 MVVM 架构和 winUI 3


创建项目

在 Visual Studio 中创建一个名为 WPF应用的项目

  • .sln 解决方案
  • .csproj C# 项目文件

.NET Framework 仅用于 Windows, 闭源, 追求稳定
.NET 开源, 持续更新


xaml 基础

WPF 采用 xaml 格式来标记 UI

App.xaml 文件中, StartupUri 用于指定初始启动窗口

1
2
3
4
5
6
7
8
9
<Application x:Class="firstWPFAppliction.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:firstWPFAppliction"

StartupUri="MainWindow.xaml">
<!--启动的窗口: StartupUri="MainWindow.xaml" -->

</Application>

布局

  • Grid: 官方文档
  • StackPanel: 官方文档

Grid 布局

Grid 布局默认一行一列

定义行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<Grid>
<Grid.RowDefinitions/>
<!-- 只有高度属性 -->
<RowDefinition Height="20"/>
<RowDefinition Height="auto"/>

<!-- 高度为剩下区域的 9/10 -->
<RowDefinition Height="1*"/>
<!-- 高度为剩下区域的 1/10 -->
<RowDefinition Height="9*"/>
<Grid.RowDefinitions/>

<TextBlock Grid.Row="0" Text="第一行"/>
<Button Grid.Row="1" Content="第二行"/>
</Grid>

可以通过 Grid.ColumnSpan 来合并两列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>

<TextBlock Text="密码"
Grid.Column="0" VerticalAlignment="Center"/>
<TextBox Grid.Column="1"/>

<!--Grid.ColumnSpan="2" 合并两列 -->
<CheckBox Content="记住密码"
Grid.ColumnSpan="2" VerticalAlignment="Center"/>
</Grid>

样式

全局样式

Margin="10" 左右上下各 10
Margin="50,0,0,0" 对应左, 上, 右, 下

作用于单个标签的样式:

1
2
<!-- 这里的 Background 是样式的属性 -->
<Button Content="测试" Background="Red"/>

单个窗口的全局样式, 作用于所有目标标签:

单个窗口的全局样式优先级高于资源字典

1
2
3
4
5
6
7
8
9
10
11
<Windows.Resource>
<!-- Target 样式作用到的目标标签类型 -->
<Style TargetType="Button">
<!-- 也可以这么写: <Style TargetType="{x:Type Button}"> -->

<!-- 各个样式属性 -->
<Setter Property="Background" Value="Red" />
<Setter Property="FontSize" Value="20" />
</Style>

</Windows.Resource>

命名样式

如果一个页面需要不同样式的按钮, 就需要用到命名样式
命名样式只作用于引用到它的目标样式
如何命名? 只需在样式标签的属性内添加 x:Key 属性命名即可

x 是什么意思? x指的的 x name space (x 命名空间)

1
2
3
<Style x:Key="随便什么名字">
...
</Style>

标签引用命名样式:

1
2
<!-- 这里用的是静态资源 -->
<Button Style="{StaticResource: 随便什么名字}"/>

静态资源样式在运行时不会随代码的改变而改变


样式继承

1
2
3
4
5
6
7
8
9
<!-- 一个全局基础样式 -->
<Style TargetType="Button">
...
</Style>

<!-- 继承全局基础样式 -->
<Style BasedOn="{StaticResource {x:Type Button}}" x:Key="命名样式" TargetType="Button" >
...
</Style>

资源字典

使用资源字典可以方便资源的管理, 同时所有窗口都可以应用在资源字典里声明的样式


在项目根目录中创建一个 TestStyle.xaml 文件(资源字典)

1
2
3
4
5
6
7
8
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<!-- 定义全局样式 -->
<Style TargetType="Button">
<Setter Property="Background" Value="Blue"/>
</Style>
</ResourceDictionary>

然后在 App.xaml 中, 定义资源字典

1
2
3
4
5
6
7
8
9
10
11
12
13
<Application.Resources>

<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- 资源字典的路径前一定要添加 "component/" -->
<ResourceDictionary Source="/项目的文件夹;component/TestStyle.xaml" />

<!-- 也这么写 ↓ -->
<ResourceDictionary Source="/TestStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

</Application.Resources>

自定义模板

当覆写按钮样式, 按钮的样式将全部消失

按钮样式是没有圆角样式的, 可以通过覆写来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<Button>
<!-- 覆写按钮样式 -->
<Button.Template>
<ControlTemplate TargetType="Button">
<!-- 设置圆角 -->
<Border Background="blue" CornerRadius="10">
<!-- 重新生成以查看更改 -->
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>

这样写会将按钮的属性固定, 可以通过数据绑定来避免属性固定

属性的绑定,一个例子:

1
<Border Background="{TemplateBinding Background}" CornerRadius="10">

这样覆写的样式目前没有交互的动画, 需要设置触发器来创建交互动画
一个例子:

1
2
3
4
5
6
7
8
9
<ControlTemplate TargetType="Button">
<!-- 触发器 -->
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!-- TargetName <Button x:Name="border" > ... -->
<Setter TargetName="border" Property="Background" Value="red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

C# 控制基础

事件可通过 属性 页面查看


点击事件

.xaml 文件定义处理事件的函数名
同名的 .xaml.cs C# 代码定义函数

单击事件 Click:

1
2
3
4
5
<Button Click="函数名" />

<!-- 一个例子 -->
<TextBlock x:Name="Text1" Text="6" HorizontalAlignment="Center"/>
<Button Click="ShowNumber" />

要访问标签, 需为标签添加命名 x:name
然后在 .xaml.cs 文件中, 通过 命名.属性 来访问其属性

1
2
3
private void ShowNumber(object sender, RoutedEventArgs e){
Text1.Text = "动态显示文字"
}

MVVM


其它

格式

关于 .xaml 的格式, 写法 1 与写法 2 等效

1
2
3
4
5
6
7
8
9
<!-- 写法 1 -->
<Button Content="测试"/>

<!-- 写法 2 -->
<Button>
<Button.Content>
测试
</Button.Content>
<Button/>

判断使用的窗口技术

通过查看 App.xaml.cs 使用的命名空间来判断:

  • System.Windows 是 WPF
  • Windows.UI.Xaml 是 UWP
  • Microsoft.UI.Xaml 是 WinUI
    • 使用了 Windows.UI.Xaml 是 WinUI 2
    • 未使用 Windows.UI.Xaml 是 WinUI 3