WPF XAML+布局+控件
一、WPF 与 XAML 简介
WPF(Windows Presentation Foundation)是微软推出的基于 .NET Framework(以及 .NET Core/5+)的现代 UI 框架,采用矢量渲染、数据绑定、样式模板等先进技术,能够构建富客户端桌面应用。
XAML(eXtensible Application Markup Language)是一种声明式 XML 语言,用于定义 WPF 的用户界面。它将界面设计与业务逻辑分离,使开发人员可以专注于 C#/VB 代码,而设计人员可以使用 Blend 等工具直接编写 XAML。
二、XAML 详解
2.1 XAML 命名空间
在XAML(可扩展应用程序标记语言)中, 命名空间是类似于C#中 using 的关键机制。 它通过 xmlns 属性将XAML中的元素标签(如 <Button>)映射到实际的.NET类库,使XAML解析器能准确定位和实例化所需的C#类型
XAML命名空间声明通常位于XAML文件的根元素中, 语法是 xmlns[:可选前缀]="命名空间标识符"。 每个 WPF XAML 文件根元素包含以下常见命名空间:
xml
<Window x:Class="WpfApp.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"
Title="MainWindow" Height="450" Width="800">
<!-- 界面内容 -->
</Window>
xmlns 默认命名空间: WPF 核心元素(控件、布局等)。
xmlns:x : XAML 专用指令,如 x:Class, x:Name, x:Static 等。
xmlns:d 和 mc:Ignorable:用于设计时支持。
XAML 语言特性命名空间 (xmlns:x):通过前缀 x: 来引用,它包含了XAML语言本身定义、与UI框架无关的一些指令和功能,例如 x:Name、x:Key、x:Class 等。详细功能见下表:
| 指令 | 描述 |
|---|---|
| x:Class | 指定XAML文件编译后生成的partial类的命名空间和类名,即代码隐藏文件的类名。 |
| x:Name | 为XAML元素设置一个唯一标识符,可以在代码隐藏文件中直接访问该对象。 |
| x:Key | 为资源字典中的每个资源定义一个唯一的键,通常用于 StaticResource 或 DynamicResource 标记扩展进行检索。 |
| x:TypeArguments | 为泛型类指定泛型参数的类型。 |
2.2 XAML 语法基础
对象元素: 使用尖括号声明,如 <Button>。
特性(Attribute): 设置属性或事件,如 Content="Click"。
嵌套内容: 支持子元素,例如 Grid 中放置多个控件。
XAML 中的值转换: 内置类型转换器将字符串转换为对应类型(如 Background="Red" -> SolidColorBrush)。
xml
<!-- 带内容的 Grid 容器 -->
<Grid>
<!-- 创建一个 Button 对象 -->
<Button Background="Red" Height="50" Width="100" Content="按钮"/>
<TextBlock Text="Hello WPF" />
</Grid>
<!--解析器会将 <Button> 转换成 new Button(),将 <Grid> 转换成 new Grid()。-->
2.3 属性元素与特性语法
特性语法 适用于简单值(字符串、数字、枚举等),直接在元素标签内设置。
xml
<Button Content="按钮" Background="Blue" Height="50" Width="100"/>
属性元素语法 是 XAML 中为复杂属性赋值的一种写法。
当属性的值无法用简单的字符串(如 "Red")表示,而需要嵌套对象、集合或更多子属性时,就用 <类型.属性名> 的形式,把属性写成独立的子元素。
实现一个渐变色按钮
xml
<Window x:Class="WPF_XMAL_Basics_Demo01.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:WPF_XMAL_Basics_Demo01"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<!-- 带内容的 Grid 容器 -->
<Grid>
<!-- 创建一个 Button 对象 -->
<Button Height="50" Width="100" Content="按钮">
<Button.Background>
<LinearGradientBrush>
<!-- Offset种0是起点 1是终点 -->
<GradientStop Color="Red" Offset="0"/>
<GradientStop Color="Yellow" Offset="0.5"/>
<GradientStop Color="Green" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
</Button>
</Grid>
</Window>
2.4 附加属性
附加属性允许父元素为子元素设置属性(例如 Grid.Row、Grid.Column)。语法为 <父元素.附加属性名>。
xml
<Grid>
<!--将Grid分为三行-->
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--
在Grid的第一行放一个红色的按钮,在第二行放一个蓝色的按钮,在第三行放一个黄色的按钮
这个时候Grid.Row 为附加属性 而Grid.Row在 Button标签中并没有这个属性,这个属性来自于父元素Grid
-->
<Button Grid.Row="0" Background="Red" Content="第一行"/>
<Button Grid.Row="1" Background="Blue" Content="第二行"/>
<Button Grid.Row="2" Background="Yellow" Content="第三行"/>
</Grid>
2.5 标记扩展
(后续会写一篇详解,关于标记拓展和数据绑定以及MVVM,这里只介绍基础概念和如何标记拓展)
标记扩展允许在运行时解析属性值,使用花括号 {} 包裹;
常用标记扩展:
| 扩展 | 示例 | 作用 |
|---|---|---|
| {Binding} | Text="{Binding UserName}" | 数据绑定 |
| {StaticResource} | Background="{StaticResource myBrush}" | 引用静态资源 |
| {x:Null} | Tag="{x:Null}" | 设置为 null |
| {x:Static} | Text="{x:Static local:Constants.AppName}" | 引用静态成员 |
| {x:Type} | DataType="{x:Type Button}" | 获取 Type 对象 |
标记扩展也可以嵌套: Text="{Binding Path={x:Static local:Paths.DefaultPath}}"。
xml
<!--绑定UserName-->
<TextBlock Text="{Binding UserName}" />
<Button Background="{StaticResource ErrorBrush}" />
2.6 代码隐藏文件
代码隐藏文件就是和 XAML 界面"配对"的那个 C# 文件,代码隐藏文件是写"逻辑"的地方,让 XAML 画出来的界面真正"活"起来。XAML 与后台代码通过 x:Class 关联。在 .xaml.cs 中使用 InitializeComponent() 加载 XAML。
InitializeComponent()是 XAML 框架提供的方法,负责将 XAML 设计图实例化为真实的控件树,并建立后台代码与界面元素的连接。它是 UI 能够显示和交互的基石。
cs
public partial class MainWindow : Window{
public MainWindow(){
InitializeComponent();
}
}
三、WPF 布局系统
WPF 的布局系统是 UI 框架的核心,它负责自动计算每个控件的大小和位置,以适应窗口大小变化、内容更新或字体缩放等动态场景。
核心思想就是容器说了算: 在 WPF 中,控件通常不自己决定位置,而是由它的父容器(如 Grid、StackPanel)来安排。每个容器有自己的布局规则(堆叠、网格、停靠等),递归地管理内部所有子元素。
3.1 布局原则
WPF 布局系统背后有几个核心的设计原则
1. 尺寸由容器决定,而非自身: 不写死 Width/Height,让父容器根据内容和规则自动分配大小。
2. 位置由容器决定,而非坐标: 避免 Canvas 绝对定位,用 Grid、StackPanel 等容器自动安排位置。
3. 使用比例和自动尺寸,而非像素: 用 * 和 Auto 按比例或内容分配空间,不依赖固定像素值。
4. 对齐与边距控制间距,而非空白元素: 用 HorizontalAlignment、Margin 等属性控制间距,不要用空元素占位。
5. 容器可以嵌套,但不要过深: 嵌套布局可行,但过深会影响性能,优先用 Grid 跨行跨列简化结构。
6. 让布局自动适应内容变化: 确保父容器能随内容动态增减而自动调整大小,必要时包裹 ScrollViewer。
7 .设计时考虑 DPI 缩放和字体: 使用与设备无关的坐标(WPF 单位),避免依赖绝对像素值,保证高 DPI 下正常显示。
只需要记住让容器决定尺寸和位置,使用比例/自动尺寸,通过对齐/边距控制间距,避免固定值和绝对坐标。
3.2 核心布局容器
这里主要介绍Grid和StackPanel两种,这两种容器基本上能解决90%及以上的问题
Grid(网格)
最强大和常用的布局容器,类似于 HTML 的 <table>。可以定义行和列,将控件放入指定单元格。
常用属性: Grid.Row, Grid.Column, Grid.RowSpan, Grid.ColumnSpan。
xml
<!--ShowGridLines属性用于显示网格线-->
<!--ShowGridLines属性用于显示网格线-->
<Grid ShowGridLines="True">
<!--Grid.RowDefinitions用于定义行-->
<Grid.RowDefinitions>
<!--RowDefinition用于定义行的高度-->
<RowDefinition Height="Auto"/>
<!-- 自适应内容高度 -->
<RowDefinition Height="*"/>
<!-- 按比例分配剩余空间 -->
<RowDefinition Height="50"/>
<!-- 固定高度 -->
</Grid.RowDefinitions>
<!--Grid.ColumnDefinitions用于定义列-->
<Grid.ColumnDefinitions>
<!--ColumnDefinition用于定义列的宽度-->
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--Grid.Row表示行索引,Grid.Column表示列索引 从下标0开始-->
<!--Grid.RowSpan表示行跨度,Grid.ColumnSpan表示列合并-->
<TextBlock Text="Header" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="1"/>
<Button Grid.Row="1" Grid.Column="0" Content="Left"/>
<Button Grid.Row="1" Grid.Column="1" Content="Right"/>
<Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Content="Footer"/>
</Grid>
StackPanel(堆叠面板)
沿水平或垂直方向顺序排列子元素,不换行。
Orientation 可选 Vertical(默认)或 Horizontal。
xml
<!--Orientation的作用是决定StackPanel中子元素的排列方向-->
<!--Orientation="Vertical"表示子元素垂直排列,Orientation="Horizontal"表示子元素水平排列-->
<StackPanel Orientation="Vertical">
<Button Content="Top"/>
<Button Content="Middle"/>
<Button Content="Bottom"/>
</StackPanel>
主要使用五种核心容器 Grid和StackPannel最常见
| 容器 | 适用场景 |
|---|---|
| Grid | 表单布局、仪表盘、整体页面框架,需要行列对齐和比例分配空间时。 |
| StackPanel | 工具栏、菜单、垂直或水平排列的简单列表,不需要换行或复杂对齐。 |
| DockPanel | 类似 Visual Studio 的窗口布局(顶部菜单+底部状态栏+左右停靠+中央内容区)。 |
| WrapPanel | 标签云、图片墙、动态添加的按钮组,空间不足时自动换行/换列。 |
| Canvas | 绘图程序、图形编辑器、需要绝对坐标定位的动画或自定义绘制元素。 |
3.3 布局通用属性
所有派生自 FrameworkElement 的控件都拥有以下重要布局属性:
| 属性 | 描述 |
|---|---|
| Width / Height | 固定宽高 |
| MinWidth / MaxWidth, MinHeight / MaxHeight | 尺寸范围限制 |
| Margin | 元素外部的空白(顺序:左,上,右,下) |
| Padding | 元素内容与边界间的空白(只有部分控件支持,如 Button) |
| HorizontalAlignment | 水平对齐:Left, Center, Right, Stretch |
| VerticalAlignment | 垂直对齐:Top, Center, Bottom, Stretch |
| Visibility | Visible, Hidden, Collapsed(Collapsed 不占空间) |
当同时设置 Width 和 HorizontalAlignment="Stretch" 时,Width 优先级更高。
四、WPF 控件详解
4.1 按钮类 (Button, RepeatButton)
WPF 按钮类控件都派生自 ButtonBase,核心能力是 单击(Click) 和 命令(Command)。
Button : 用户单击触发 Click 事件,可包含任意内容(图像、文本、布局)。
xml
<Button Click="OnSaveClick">
<StackPanel Orientation="Horizontal">
<Image Source="save.png" Width="16"/>
<TextBlock Text="Save"/>
</StackPanel>
</Button>
RepeatButton : 按住时重复触发 Click 事件(用于调节数值或滚动)。
xml
<RepeatButton Content="+" Delay="500" Interval="100" Click="Increase_Click"/>
其他按钮
| 控件 | 特点 |
|---|---|
| Button | 标准按钮,按下弹起触发一次。 |
| RepeatButton | 长按时周期性重复触发。 |
| ToggleButton | 开关状态:按下/弹起(IsChecked)。 |
| CheckBox | 勾选框,可三态(IsThreeState)。 |
| RadioButton | 单选框,同组内只能选一个。 |
4.2 文本输入与显示 (TextBox, TextBlock, Label, PasswordBox)
TextBox 最通用的文本输入控件,支持单行/多行、撤销、复制/粘贴。常用于普通表单输入、备注框、可编辑字段
关联属性
| 属性 | 说明 |
|---|---|
| Text | 当前文本内容(用于绑定)。 |
| TextWrapping | 是否换行(多行输入常用 Wrap)。 |
| AcceptsReturn | 是否允许输入回车换行(多行必须设为 true)。 |
| AcceptsTab | 是否允许 Tab 键输入(通常保留用于焦点导航)。 |
| MaxLength | 最大字符数。 |
| SpellCheck.IsEnabled | 启用拼写检查(需设置 xml:lang)。 |
| IsReadOnly | 只读模式(视觉上可区分)。 |
TextBlock 量级只读文本控件,性能最好,支持内联元素(Run、LineBreak、InlineUIContainer)。常用于标签、说明文字、动态消息、需要部分高亮的文本。
关键属性
| 属性 | 说明 |
|---|---|
| Text | 纯文本内容(最常用)。 |
| TextWrapping | 换行方式(NoWrap / Wrap / WrapWithOverflow)。 |
| TextTrimming | 溢出裁切(None / CharacterEllipsis / WordEllipsis)。 |
| TextDecorations | 下划线、删除线等。 |
| Inlines | 内联元素集合(比纯文本更灵活)。 |
Label 支持访问键(Access Key)的文本控件,通常作为其他控件的标题。常用于表单字段标签(如"姓名:"),需快捷键定位到输入框。
关键属性
| 属性 | 说明 |
|---|---|
| Target | 指定按下 Alt+快捷键时焦点转移到的目标控件。 |
| Content(继承自ContentControl) | 可以是文本或任意UI元素。 |
访问键语法: 在文本中用下划线 _ 定义快捷键(例如 _Name 显示为 "Name",按 Alt+N 定位到 Target)。
xml
<Label Target="{Binding ElementName=txtName}">_姓名:</Label>
<TextBox x:Name="txtName"/>
PasswordBox 密码输入控件,输入的字符被掩码(·或*),且不会在内存中保留明文。
关键属性
| 属性 | 说明 |
|---|---|
| Password | 当前密码明文(不推荐绑定,违反安全设计)。 |
| SecurePassword | 返回 SecureString(更安全)。 |
| PasswordChar | 掩码字符(默认 ●)。 |
| MaxLength | 最大长度。 |
获取密码的安全方式: 使用 PasswordBox.Password 仅在需要时读取,避免缓存。
文本选择
| 控件 | 需求 |
|---|---|
| TextBlock | 态文本(纯展示) |
| Label | 表单标签(带快捷键) |
| TextBox | 单行/多行普通文本输入 |
| PasswordBox | 密码输入 |
| RichTextBox带格式的文本编辑 | (字号、颜色等) |
| FlowDocumentScrollViewer RichTextBox(只读) | 大量只读格式化文本(内置滚动) |
4.3 选择控件 (CheckBox, RadioButton, ToggleButton)
WPF 的选择控件是让用户从一组选项中做出选择的控件,主要分为三类:布尔选择(是否)、单项选择(互斥)、多项选择(可多选)。
| 控件 | 行为 |
|---|---|
| CheckBox | 三态(选中、取消、不确定),用于布尔选项 |
| RadioButton | 互斥选择,相同 GroupName 为一组 |
| ToggleButton | 具有选中/未选中两种状态的按钮,常用于工具条 |
公共属性(继承自 ToggleButton)
| 属性 | 说明 |
|---|---|
| IsChecked | bool? 类型(true/false/null,仅 CheckBox 支持 null 表示不确定状态)。 |
| IsThreeState | 仅 CheckBox 有效,启用第三态(IsChecked = null)。 |
xml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<ToggleButton Grid.Row="0" Content="开关"></ToggleButton>
<CheckBox Grid.Row="1" Content="记住我" IsChecked="True" Checked="CheckBox_Checked"/>
<RadioButton Grid.Row="2" Content="男" GroupName="Gender" IsChecked="True"/>
<RadioButton Grid.Row="3" Content="女" GroupName="Gender"/>
</Grid>
选择: 需要勾选框用 CheckBox,需要单选用 RadioButton,只需要按下/弹起外观的按钮用 ToggleButton
4.4 列表控件 (ListBox, ComboBox, ListView)
WPF 的列表控件用于展示集合数据,并支持选择、编辑、分组、排序等交互。核心基类是 ItemsControl,它定义了数据绑定和项模板化的基础。
公共基类 ItemsControl 的核心属性
| 属性 | 作用 |
|---|---|
| ItemsSource | 绑定数据集合(实现 IEnumerable,推荐 ObservableCollection)。 |
| Items | 直接添加静态项(XAML 中写 )。 |
| DisplayMemberPath | 指定显示数据对象的哪个属性(简单场景)。 |
| ItemTemplate | 数据模板,自定义每个项的呈现方式(比 DisplayMemberPath 更强大)。 |
| ItemContainerStyle | 为每个项容器(如 ListBoxItem)设置样式。 |
| SelectedItem / SelectedIndex | 当前选中项(单项)。 |
| ItemsPanel | 指定布局面板(默认 StackPanel,可换成 WrapPanel 等)。 |
ListBox 选择模式:SelectionMode = Single(默认)/ Extended(Ctrl/Shift 多选)/ Multiple(简单多选)。
SelectedItems 属性(只读,通常用代码或绑定自定义) 默认开启虚拟化(VirtualizingStackPanel),大数据量友好。
xml
<ListBox ItemsSource="{Binding Users}"
SelectedItem="{Binding SelectedUser}"
DisplayMemberPath="Name"/>
ComboBox IsEditable 让用户可输入文本(需配合 IsTextSearchEnabled 搜索)。
常用属性: DropDownHeight,MaxDropDownHeight。
事件: SelectionChanged,DropDownOpened / Closed。
xml
<ComboBox ItemsSource="{Binding Cities}"
SelectedItem="{Binding SelectedCity}"
IsEditable="True"/>
ListView 默认视图:GridView 可显示多列 支持自定义视图(如图标模式),通过设置 View 为自定义 ViewBase。
xml
<ListView ItemsSource="{Binding Files}">
<ListView.View>
<GridView>
<GridViewColumn Header="名称" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="大小" DisplayMemberBinding="{Binding Size}"/>
</GridView>
</ListView.View>
</ListView>
列表选择
| 控件 | 需求 |
|---|---|
| ListBox | 普通列表,支持单选/多选 |
| ComboBox | 空间有限的单选下拉 |
| ListView + GridView 或 DataGrid | 多列表格数据 |
| DataGrid | 复杂表格(编辑、排序、筛选) |
| TreeView | 层次数据(目录、组织) |
| ItemsControl(自定义模板) | 只展示数据(无选择) |
4.5 数据表格 (DataGrid)
DataGrid 是 WPF 中最强大的表格控件,专门用于展示和编辑结构化数据。它内置了排序、筛选、编辑、分组、行细节等丰富功能,非常适合处理类似数据库或 Excel 的二维数据。
需要编辑、增删、复杂交互的表格选 DataGrid;只读多列选 ListView。
核心能力
列类型:文本列、复选框列、下拉列、超链接列、自定义模板列
交互:排序、调整列宽/顺序、编辑(单元格/行)、增删行
视觉:交替行背景、行细节展开、冻结列、网格线控制
选择:单选/多选(单元/整行)
验证:内置错误提示(红色边框/感叹号)
常用属性
| 属性 | 作用 |
|---|---|
| AutoGenerateColumns | 自动生成列(默认true) |
| CanUserAddRows | 底部显示新行占位符 |
| CanUserSortColumns | 启用列排序 |
| IsReadOnly | 整体只读 |
| SelectionMode / SelectionUnit | 选择模式(单/多选,单元/整行) |
| FrozenColumnCount | 冻结左侧列数 |
| RowDetailsTemplate | 定义行展开区域 |
xml
<Window x:Class="WPF_Control_Demo03.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF_Control_Demo03"
Title="MainWindow" Height="450" Width="800">
<Grid>
<!--这里AutoGenerateColumns="True"可以不写,因为默认为True,这里写上能看的更直观一点-->
<DataGrid x:Name="MyGrid" AutoGenerateColumns="True" />
</Grid>
</Window>
后台代码
cs
using System.Windows;
namespace WPF_Control_Demo03{
public partial class MainWindow : Window{
public MainWindow(){
InitializeComponent();
// 造一个简单的数据集合(匿名类型)
var data = new[]{
new { 姓名 = "张三", 年龄 = 20, 城市 = "北京" },
new { 姓名 = "李四", 年龄 = 25, 城市 = "上海" },
new { 姓名 = "王五", 年龄 = 22, 城市 = "广州" }
};
MyGrid.ItemsSource = data;
}
}
}
运行后表格自动生成三列:姓名、年龄、城市,三行数据显示出来,支持排序、列宽调整。
只需给 DataGrid.ItemsSource 赋一个集合,设置 AutoGenerateColumns="True",就能立刻显示表格。
4.6 图像控件 (Image)
显示位图(BMP、PNG、JPG、ICO、GIF 等)
xml
<Image Source="Images/logo.png" Width="100" Stretch="Uniform"/>
常用属性
| 属性 | 作用 |
|---|---|
| Source | 指定图像源(BitmapImage 或图像路径/URI)。 |
| Stretch | 控制图像在控件内的缩放方式:Fill(拉伸填充)、Uniform(等比例完整显示) UniformToFill(等比例裁剪填充)、None(原始尺寸)。 |
| StretchDirection | 限制拉伸方向:UpOnly(仅放大)、DownOnly(仅缩小)、Both(任意)。 |
| Width Height | 显式设置控件尺寸(受 Stretch 影响)。 |
| MaxWidth MaxHeight | 最大尺寸限制。 |
| Opacity | 透明度(0-1)。 |
| RenderTransform | 变换(旋转、缩放等)。 |
| Clip | 裁剪几何形状。 |
4.7 容器控件 (GroupBox, Expander, TabControl)
容器控件是专门用于布局和容纳其他元素的控件,它们负责子元素的排列、尺寸分配和位置管理。所有容器控件都继承自 Panel 抽象类。
常用容器控件一览
| 容器 | 布局特点 | 适用场景 |
|---|---|---|
| Grid | 表格布局(行/列),最强大灵活 | 复杂表单、整体页面框架 |
| StackPanel | 水平或垂直堆叠 | 工具栏、菜单、简单列表 |
| WrapPanel | 流式布局,空间不足时换行/换列 | 标签云、图片墙 |
| DockPanel | 子元素停靠(上下左右),最后一个填充剩余 | 窗口布局(菜单栏+状态栏+中央区) |
| Canvas | 绝对坐标定位(Left/Top) | 绘图、图形编辑器、精确放置 |
| UniformGrid | 均分行列,所有单元格大小相同 | 棋盘、按钮矩阵 |
| Border | 装饰容器,可绘制边框、背景、圆角 | 包裹单个元素,提供视觉边界 |
| ScrollViewer | 提供滚动区域 | 当内容超出可视区域时 |
| GroupBox | 带标题边框的容器 | 分组设置区域 |
| Expander | 可折叠/展开的容器 | 隐藏高级选项 |
| TabControl | 选项卡容器,多页内容切换 | 多页面视图 |
| Frame / NavigationWindow | 页面导航容器 | 导航型应用(XAML 页面) |
布局容器(Grid, StackPanel 等)负责排列逻辑。
装饰容器(Border, ScrollViewer)为内容添加附加功能。
内容容器(GroupBox, Expander)提供扩展的视觉和行为。
优先使用 Grid 做主布局,局部用 StackPanel 或 WrapPanel,需要滚动用 ScrollViewer,绝对定位只用 Canvas。
五、综合示例
实现用户信息表单
xaml
xml
<Window x:Class="WPF_User_Information_Form_Test.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:local="clr-namespace:WPF_User_Information_Form_Test"
Title="用户信息表" Height="400" Width="600">
<Grid Margin="10">
<!-- 用户信息表格制作 -->
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="用户信息表" FontSize="20" FontWeight="Bold" HorizontalAlignment="Center" Grid.Row="0" Grid.ColumnSpan="2" Margin="0,0,0,10"/>
<!-- 姓名 -->
<Label Content="姓名:" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"/>
<TextBox Text="{Binding UserName}" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center"/>
<!--性别-->
<Label Content="性别:" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center"/>
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal">
<!--这里默认选择男-->
<RadioButton GroupName="Gender" Content="男" IsChecked="True"/>
<RadioButton GroupName="Gender" Content="女" Margin="10,0,0,0"/>
</StackPanel>
<!--年龄-->
<Label Content="年龄:" Grid.Row="3" Grid.Column="0" VerticalAlignment="Center"/>
<TextBox Text="{Binding UserAge}" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center"/>
<!--城市-->
<Label Content="城市:" Grid.Row="4" Grid.Column="0" VerticalAlignment="Center"/>
<ComboBox x:Name="MyCity" Grid.Row="4" Grid.Column="1" Margin="5" ItemsSource="{Binding CityList}"/>
<!-- 兴趣爱好 -->
<Label Grid.Row="5" Grid.Column="0" Content="兴趣:" VerticalAlignment="Center"/>
<StackPanel Grid.Row="5" Grid.Column="1" Margin="5" Orientation="Horizontal">
<CheckBox Content="唱" Margin="0,2"/>
<CheckBox Content="跳" Margin="0,2"/>
<CheckBox Content="rap" Margin="0,2"/>
<CheckBox Content="篮球" Margin="0,2"/>
</StackPanel>
<!--备注-->
<Label Content="备注:" Grid.Row="6" Grid.Column="0" VerticalAlignment="Center"/>
<!--AcceptsReturn="True"按下回车换行-->
<!--VerticalScrollBarVisibility="Auto"内容超出文本框高度时,自动显示垂直滚动条;内容不足时隐藏。-->
<!--TextWrapping="Wrap"文本超出控件宽度时自动强制换行,长单词也会拆分换行;-->
<TextBox Grid.Row="6" Grid.Column="1" Margin="5" Height="60" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap"/>
<!-- 按钮 -->
<StackPanel Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,10,0,0">
<Button Content="确定" Background="Green" Width="80" Height="30" Margin="5" VerticalAlignment="Top" Click="OkButton_Click"/>
<Button Content="取消" Background="Red" Width="80" Height="30" Margin="5" VerticalAlignment="Top" Click="CancelButton_Click"/>
</StackPanel>
</Grid>
</Window>
后台代码
cs
using System.Windows;
namespace WPF_User_Information_Form_Test{
public partial class MainWindow : Window{
public MainWindow(){
InitializeComponent();
var data = new[]{"北京" ,"上海" ,"广州" };
MyCity.ItemsSource = data;
}
private void OkButton_Click(object sender, RoutedEventArgs e){
// 收集数据并处理
MessageBox.Show("信息已保存");
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e){
MessageBox.Show("信息未保存");
this.DialogResult = true;
}
}
}
运行结果
