Day 2 - XAML 布局
建议用时:210-240 分钟
你将学会什么
- 用
StackPanel做一列或一行的简单排列。 - 用
Grid做“几行几列”的窗口结构。 - 用
DockPanel做“顶部、左侧、主内容区”的页面骨架。 - 分清
Margin和Padding,知道空间到底加在控件外面还是里面。 - 理解
Auto、固定宽度、*这三种尺寸写法。 - 把一个商品管理界面拆成“标题区、列表区、详情区”。
本页只讲布局,不讲数据绑定、不讲点击事件、不讲样式系统。先把控件摆明白,后面再让界面和 C# 数据连起来。
本页固定顺序
- 先学第一部分:弄懂今天最小、最重要的知识,并运行短例子。
- 再学第二部分:把刚学的知识组合成一个完整例子。
- 然后做第三部分:自己跟着敲,再完成重复训练和每日小测。
- 最后做第四部分:先独立完成作业,再用完整答案检查。
学习衔接
上一页学习的是“Avalonia 环境与运行”,今天继续学习“XAML 布局”。先使用上一页已经会的写法,再只增加今天这个新知识点;如果前置内容还不能独立敲出,先回上一页复习,不要硬跳。
今天的最低通过线
第一次学习不要求背完整页。完成下面 3 项,就可以继续:
- 能用自己的话说明“XAML 布局”解决什么问题。
- 把第一部分的短例子亲手敲完,并确认每个例子都能运行。
- 不看完整答案完成第三部分至少前 3 个例子,再主动改一个值观察结果。
第一部分:先学原理和最小知识
这一部分从最小知识开始。先读解释,再把紧跟着的短例子敲一遍。布局的核心不是背属性,而是先能回答三个问题:页面分几块、每块多大、控件放在哪一块。
1. 什么是布局容器
布局容器就是“帮子控件排位置的控件”。比如:
StackPanel:让里面的控件按一个方向排队。Grid:把空间切成行和列,让控件放到指定格子里。DockPanel:让控件贴到顶部、底部、左侧、右侧,剩下的位置给主内容。Border:给一个区域加边框、内边距,也常用来把一组控件包起来。
桌面窗口不是直接把按钮丢进去就结束。你要先放一个布局容器,再把 TextBlock、TextBox、Button、ListBox 这些控件放进容器。
2. StackPanel:按顺序排队
StackPanel 适合做简单区域,比如登录表单、按钮组、说明文字列表。
常用属性:
| 属性 | 作用 | 例子 |
|---|---|---|
Orientation="Vertical" | 从上到下排 | 一组输入框 |
Orientation="Horizontal" | 从左到右排 | 保存、取消两个按钮 |
Spacing="8" | 每个子控件之间留 8 像素 | 控件不会挤在一起 |
Margin="20" | 整个 StackPanel 和外部保持距离 | 页面四周留白 |
StackPanel 的好处是简单。它的限制是:它不适合做“左侧标签、右侧输入框”这种严格对齐的表单,因为它只能按一条线排。
3. Grid:按行列切页面
Grid 是最重要的布局容器。只要页面稍微复杂,通常就会用 Grid。
Grid 的写法分三步:
- 用
RowDefinitions定义有几行。 - 用
ColumnDefinitions定义有几列。 - 在子控件上写
Grid.Row和Grid.Column,指定控件放在哪一格。
例如:
<Grid RowDefinitions="Auto,*" ColumnDefinitions="220,*">这句话的意思是:
RowDefinitions="Auto,*":窗口分两行,第一行按内容高度,第二行占剩余高度。ColumnDefinitions="220,*":窗口分两列,第一列固定 220 像素,第二列占剩余宽度。
4. Auto、固定尺寸、* 的区别
布局尺寸最容易混乱,先记住这三类。
| 写法 | 含义 | 适合用在哪里 |
|---|---|---|
Auto | 内容需要多大就给多大 | 标题行、按钮行、标签列 |
220 | 固定 220 像素 | 左侧菜单、侧边栏 |
* | 占剩余空间 | 主内容区、列表区、详情区 |
2* | 占剩余空间的两份 | 两块内容按比例分配 |
例子:
<Grid ColumnDefinitions="200,*">左边固定 200,右边拿走剩下所有宽度。
<Grid ColumnDefinitions="*,2*">剩余宽度分成 3 份,左边 1 份,右边 2 份。
5. Grid.Row 和 Grid.Column
Grid 的行列从 0 开始数,不是从 1 开始。
<TextBlock Grid.Row="0" Grid.Column="0" Text="名称" />
<TextBox Grid.Row="0" Grid.Column="1" />这两行表示:
TextBlock放在第 0 行第 0 列。TextBox放在第 0 行第 1 列。
如果你忘记写 Grid.Row 和 Grid.Column,控件通常都会落在第 0 行第 0 列,看起来就像叠在一起。
6. Grid.ColumnSpan 和 Grid.RowSpan
有些控件不只占一个格子,比如标题要横跨左右两列。
<TextBlock Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Text="商品管理" />Grid.ColumnSpan="2" 的意思是:从当前列开始,横向占 2 列。
同理,Grid.RowSpan="2" 表示纵向占 2 行。
7. Margin 和 Padding 的区别
这两个属性都和空间有关,但位置完全不同。
| 属性 | 空间加在哪里 | 可以怎么理解 |
|---|---|---|
Margin | 控件外面 | 控件和别的控件之间的距离 |
Padding | 控件里面 | 边框和内部内容之间的距离 |
例如:
<Border Margin="16" Padding="12">意思是:
Margin="16":这个Border和外面的东西保持 16 像素距离。Padding="12":Border的边框和里面的内容保持 12 像素距离。
如果内容贴着边框,通常加 Padding。如果两个区域挤在一起,通常加 Margin 或 Grid 的 RowSpacing、ColumnSpacing。
8. RowSpacing 和 ColumnSpacing
Grid 里控件太挤,不一定要给每个控件单独写 Margin。
<Grid RowSpacing="10" ColumnSpacing="12">这表示:
- 每一行之间空 10 像素。
- 每一列之间空 12 像素。
表单里推荐优先使用 RowSpacing 和 ColumnSpacing,比给每个输入框单独写 Margin 更整齐。
9. HorizontalAlignment 和 VerticalAlignment
对齐属性决定控件在自己那一格里怎么放。
| 属性值 | 含义 |
|---|---|
Left | 靠左 |
Center | 居中 |
Right | 靠右 |
Stretch | 拉伸填满可用空间 |
常见用法:
<Button Content="保存"
HorizontalAlignment="Right" />按钮会靠右。输入框通常不需要写这个属性,让它默认拉伸,占满右侧空间。
10. DockPanel:先贴边,再填剩余空间
DockPanel 常用来做大骨架。
<DockPanel>
<TextBlock DockPanel.Dock="Top" Text="顶部标题" />
<ListBox DockPanel.Dock="Left" Width="200" />
<TextBlock Text="剩余空间" />
</DockPanel>它的读取顺序是从上往下:
- 第一个控件贴到顶部。
- 第二个控件贴到左侧。
- 最后一个控件填剩下的位置。
DockPanel 适合做整体区域,Grid 适合做精确表单。实际项目里经常把它们组合使用。
11. 写布局时的思考顺序
不要从按钮开始想,要先从页面结构开始想。
- 这个窗口分几个大区域?
- 这些大区域是上下分,还是左右分?
- 哪些区域固定大小,哪些区域应该跟着窗口变大?
- 哪些控件要对齐?
- 哪些地方需要外边距或内边距?
按照这个顺序想,布局就不会乱。
XAML 布局常用属性速查
| 控件/属性 | 作用 | 常见写法 |
|---|---|---|
StackPanel | 横向或纵向排列 | Orientation="Vertical" |
Grid | 行列布局 | RowDefinitions="Auto,*" |
DockPanel | 上下左右停靠 | DockPanel.Dock="Top" |
Margin | 外边距 | Margin="16" |
Padding | 内边距 | 常用于 Border |
Spacing | 子元素间距 | Spacing="8" |
HorizontalAlignment | 水平方向对齐 | Left、Center、Stretch |
VerticalAlignment | 垂直方向对齐 | Top、Center、Stretch |
Grid.Row | 放到第几行 | Grid.Row="1" |
Grid.Column | 放到第几列 | Grid.Column="2" |
布局判断顺序:
只是上下排列 -> StackPanel
需要左右区域或表单两列 -> Grid
需要顶部工具栏、底部状态栏 -> DockPanel
需要边框和内边距 -> Border第二部分:把知识组合成完整例子
这一部分只看最终结构。你不需要马上记住每个属性,只要先知道:Avalonia 的界面不是“随便放控件”,而是先选布局容器,再把控件放进容器里。
今天最终要做出的界面结构
这个窗口分成两行两列:
- 第一行是标题,标题横跨左右两列。
- 第二行左侧是商品列表。
- 第二行右侧是商品详情表单。
把下面内容放到 Views/MainWindow.axaml,可以直接运行。
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ProductApp.Views.MainWindow"
Width="760"
Height="460"
Title="商品管理布局练习">
<Grid RowDefinitions="Auto,*"
ColumnDefinitions="220,*"
RowSpacing="12"
ColumnSpacing="16"
Margin="16">
<TextBlock Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Text="商品管理"
FontSize="24"
FontWeight="Bold" />
<Border Grid.Row="1"
Grid.Column="0"
BorderBrush="#DDDDDD"
BorderThickness="1"
Padding="12">
<StackPanel Spacing="8">
<TextBlock Text="商品列表"
FontWeight="Bold" />
<ListBox>
<ListBoxItem Content="Keyboard" />
<ListBoxItem Content="Mouse" />
<ListBoxItem Content="Monitor" />
</ListBox>
</StackPanel>
</Border>
<Border Grid.Row="1"
Grid.Column="1"
BorderBrush="#DDDDDD"
BorderThickness="1"
Padding="16">
<Grid RowDefinitions="Auto,Auto,Auto,Auto,*"
ColumnDefinitions="Auto,*"
RowSpacing="10"
ColumnSpacing="12">
<TextBlock Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Text="商品详情"
FontSize="18"
FontWeight="Bold" />
<TextBlock Grid.Row="1"
Grid.Column="0"
Text="名称"
VerticalAlignment="Center" />
<TextBox Grid.Row="1"
Grid.Column="1"
Text="Keyboard" />
<TextBlock Grid.Row="2"
Grid.Column="0"
Text="价格"
VerticalAlignment="Center" />
<TextBox Grid.Row="2"
Grid.Column="1"
Text="199" />
<StackPanel Grid.Row="3"
Grid.Column="1"
Orientation="Horizontal"
Spacing="8">
<Button Content="保存" />
<Button Content="取消" />
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>先用一句话理解
外层 Grid 负责把窗口切成大区域;左侧 Border 负责包住列表;右侧 Border 负责包住表单;里面的小 Grid 负责把“名称、价格、输入框、按钮”摆整齐。
第三部分:跟着敲代码
从这里开始动手。每个例子都可以完整替换 Views/MainWindow.axaml。每敲完一个例子就运行一次:
dotnet run如果你的项目名不是 ProductApp,把 x:Class="ProductApp.Views.MainWindow" 里的 ProductApp 改成你的项目名。其他地方先不要改。
例子 1:用 StackPanel 做竖排页面
这个例子先练最简单的排版:标题、输入框、按钮从上到下排。
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ProductApp.Views.MainWindow"
Width="420"
Height="280"
Title="StackPanel 竖排">
<StackPanel Margin="20"
Spacing="10">
<TextBlock Text="商品录入"
FontSize="22"
FontWeight="Bold" />
<TextBlock Text="商品名称" />
<TextBox PlaceholderText="请输入商品名称" />
<TextBlock Text="商品价格" />
<TextBox PlaceholderText="请输入商品价格" />
<Button Content="保存" />
</StackPanel>
</Window>这段代码要看懂三点:
StackPanel是父容器,里面的控件默认从上到下排。Margin="20"让整块内容不要贴着窗口边缘。Spacing="10"让每个控件之间有距离。
例子 2:用 StackPanel 做横排按钮
按钮通常是横向排列,所以把 Orientation 改成 Horizontal。
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ProductApp.Views.MainWindow"
Width="420"
Height="220"
Title="StackPanel 横排">
<StackPanel Margin="20"
Spacing="16">
<TextBlock Text="是否保存当前商品?"
FontSize="20" />
<StackPanel Orientation="Horizontal"
Spacing="8">
<Button Content="保存" />
<Button Content="取消" />
<Button Content="删除" />
</StackPanel>
</StackPanel>
</Window>这里有两个 StackPanel:
- 外层负责上下排:文字在上,按钮区在下。
- 内层负责左右排:三个按钮横向排列。
例子 3:用 Grid 做两列表单
表单通常要让“标签”和“输入框”对齐,这时用 Grid 比 StackPanel 更合适。
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ProductApp.Views.MainWindow"
Width="480"
Height="280"
Title="Grid 表单">
<Grid RowDefinitions="Auto,Auto,Auto"
ColumnDefinitions="Auto,*"
RowSpacing="10"
ColumnSpacing="12"
Margin="20">
<TextBlock Grid.Row="0"
Grid.Column="0"
Text="名称"
VerticalAlignment="Center" />
<TextBox Grid.Row="0"
Grid.Column="1"
Text="Keyboard" />
<TextBlock Grid.Row="1"
Grid.Column="0"
Text="价格"
VerticalAlignment="Center" />
<TextBox Grid.Row="1"
Grid.Column="1"
Text="199" />
<Button Grid.Row="2"
Grid.Column="1"
Content="保存"
HorizontalAlignment="Right" />
</Grid>
</Window>这里的关键点:
ColumnDefinitions="Auto,*":左列按文字宽度,右列占剩余空间。Grid.Row="1"表示第 2 行,因为行号从 0 开始。Button放在第 2 行第 1 列,所以它会和输入框左边对齐。
例子 4:用 Grid 做页面大分区
页面通常不是只有一个表单,而是有标题、左侧列表、右侧详情。
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ProductApp.Views.MainWindow"
Width="720"
Height="420"
Title="Grid 页面分区">
<Grid RowDefinitions="Auto,*"
ColumnDefinitions="200,*"
RowSpacing="12"
ColumnSpacing="12"
Margin="16">
<TextBlock Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Text="商品管理"
FontSize="24"
FontWeight="Bold" />
<ListBox Grid.Row="1"
Grid.Column="0">
<ListBoxItem Content="Keyboard" />
<ListBoxItem Content="Mouse" />
<ListBoxItem Content="Monitor" />
</ListBox>
<TextBlock Grid.Row="1"
Grid.Column="1"
Text="右侧这里以后显示商品详情。" />
</Grid>
</Window>注意标题这一行:
Grid.ColumnSpan="2"标题从第 0 列开始,占 2 列,所以它能横跨左侧列表和右侧详情。
例子 5:用 Border 做一个有内边距的区域
Border 经常用来包住一块内容,让这块内容看起来是一个独立区域。
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ProductApp.Views.MainWindow"
Width="460"
Height="300"
Title="Border 区域">
<Border Margin="20"
Padding="16"
BorderBrush="#DDDDDD"
BorderThickness="1">
<StackPanel Spacing="10">
<TextBlock Text="商品详情"
FontSize="20"
FontWeight="Bold" />
<TextBlock Text="名称:Keyboard" />
<TextBlock Text="价格:199" />
<Button Content="编辑" />
</StackPanel>
</Border>
</Window>这段代码里:
Margin="20"是Border和窗口边缘的距离。Padding="16"是边框和内部文字、按钮之间的距离。BorderThickness="1"表示边框粗细是 1。
例子 6:用 DockPanel 做顶部和左侧结构
DockPanel 适合快速做“顶部标题 + 左侧菜单 + 中间内容”的结构。
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ProductApp.Views.MainWindow"
Width="720"
Height="420"
Title="DockPanel 页面骨架">
<DockPanel Margin="16">
<TextBlock DockPanel.Dock="Top"
Text="商品管理"
FontSize="24"
FontWeight="Bold"
Margin="0,0,0,12" />
<ListBox DockPanel.Dock="Left"
Width="200"
Margin="0,0,12,0">
<ListBoxItem Content="Keyboard" />
<ListBoxItem Content="Mouse" />
<ListBoxItem Content="Monitor" />
</ListBox>
<Border BorderBrush="#DDDDDD"
BorderThickness="1"
Padding="16">
<TextBlock Text="这里是剩余空间,可以放详情表单。" />
</Border>
</DockPanel>
</Window>这段代码的顺序很重要:
- 标题先出现,所以贴到顶部。
- 列表第二个出现,所以贴到左侧。
- 最后的
Border没有写DockPanel.Dock,它会占剩余空间。
例子 7:把 Grid 和 Border 组合成完整表单
这一段接近真实页面:外面用 Border 包区域,里面用 Grid 对齐表单字段。
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ProductApp.Views.MainWindow"
Width="560"
Height="340"
Title="详情表单">
<Border Margin="20"
Padding="16"
BorderBrush="#DDDDDD"
BorderThickness="1">
<Grid RowDefinitions="Auto,Auto,Auto,Auto"
ColumnDefinitions="Auto,*"
RowSpacing="10"
ColumnSpacing="12">
<TextBlock Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Text="商品详情"
FontSize="20"
FontWeight="Bold" />
<TextBlock Grid.Row="1"
Grid.Column="0"
Text="名称"
VerticalAlignment="Center" />
<TextBox Grid.Row="1"
Grid.Column="1"
Text="Keyboard" />
<TextBlock Grid.Row="2"
Grid.Column="0"
Text="库存"
VerticalAlignment="Center" />
<TextBox Grid.Row="2"
Grid.Column="1"
Text="30" />
<StackPanel Grid.Row="3"
Grid.Column="1"
Orientation="Horizontal"
Spacing="8"
HorizontalAlignment="Right">
<Button Content="保存" />
<Button Content="取消" />
</StackPanel>
</Grid>
</Border>
</Window>这一段要重点看组合关系:
Border只负责外框和内边距。Grid负责行列。TextBlock负责显示文字。TextBox负责显示输入框。StackPanel负责让两个按钮横向排。
常见错误和修法
| 错误 | 为什么错 | 修法 |
|---|---|---|
所有控件都堆进一个 StackPanel | 页面一复杂就难排列 | 需要行列时用 Grid |
Grid.Row 写了但没定义行 | 控件位置不会按预期 | 先写 RowDefinitions |
| 边距和间距混用 | 页面看起来不稳定 | 外部用 Margin,内部间距用 Spacing |
| 控件被挤没了 | 行高或列宽设置不合适 | 检查 Auto、*、固定宽度 |
| XAML 标签没闭合 | 编译直接报错 | 每个开始标签都要有结束或自闭合 |
小白重复敲写训练
每次只练一种布局,看到效果后再组合。
训练 1:竖向 StackPanel
<StackPanel Margin="20" Spacing="8">
<TextBlock Text="商品名称" />
<TextBox Text="Keyboard" />
<Button Content="保存" />
</StackPanel>改动任务:增加“商品价格”和第二个输入框。
训练 2:横向排列
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Content="新增" />
<Button Content="保存" />
<Button Content="删除" />
</StackPanel>第二遍交换三个按钮的顺序。
训练 3:两列 Grid
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto" ColumnSpacing="12" RowSpacing="8">
<TextBlock Grid.Row="0" Grid.Column="0" Text="名称" />
<TextBox Grid.Row="0" Grid.Column="1" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="价格" />
<TextBox Grid.Row="1" Grid.Column="1" />
</Grid>第三遍增加第三行“库存”。
每日小测
做完本页后,用这 5 题检查是否真的掌握。
1. 判断题
本页的目标不是只把代码运行起来,还要能说清楚“为什么这样写”。
答案:对。能运行只是第一步,能解释原理、常用操作和常见错误,才说明本页内容进入了可复用能力。
2. 填空题
本页主题是:XAML 布局。今天至少要掌握的 3 个点是:
1. 用 `StackPanel` 做一列或一行的简单排列。
2. 用 `Grid` 做“几行几列”的窗口结构。
3. 用 `DockPanel` 做“顶部、左侧、主内容区”的页面骨架。答案:以上 3 点必须能用自己的代码跑通,不能只停留在阅读。
3. 流程题
遇到本页相关功能时,先按什么顺序处理?
答案:先看完整例子,确认最终效果;再读原理和名词;然后跟着第三部分从空项目敲代码;最后对照作业答案检查。
4. 找错误题
如果本页代码运行失败,第一步应该做什么?
答案:先看终端或 IDE 里的第一条错误,找到文件名和行号;不要同时改很多地方。再回到本页的“常见错误和修法”表格,对照错误类型逐项排查。
5. 改需求题
在本页完整例子跑通后,至少改一个小需求。
可选改法:
- 改一个字段名称。
- 多加一个校验条件。
- 多输出一行结果。
- 把固定数据改成用户输入。
- 把一次处理改成多条数据处理。
答案标准:修改后能重新运行,并能说明这次修改影响了哪一段逻辑。重点检查:用 StackPanel 做一列或一行的简单排列。。
上位机专项练习
布局决定监控界面能否看清。用 Grid 分区,用 StackPanel 排列同类控件。
下面 3 个例子都要亲手敲。先运行原代码,再完成每个例子后面的改动任务。
专项例子 1:三行监控布局
<Grid RowDefinitions="Auto,*,Auto" Margin="20">
<TextBlock Grid.Row="0" Text="设备总览" FontSize="28" />
<Border Grid.Row="1" Background="#F2F4F7" Margin="0,16">
<TextBlock Text="实时数据区域" Margin="16" />
</Border>
<TextBlock Grid.Row="2" Text="通信正常" />
</Grid>运行结果或界面效果:
标题、数据区、状态栏从上到下排列改动任务: 把中间区域文字改成“趋势图区域”。
专项例子 2:两列参数布局
<Grid ColumnDefinitions="160,*" RowDefinitions="Auto,Auto" Margin="20">
<TextBlock Grid.Row="0" Grid.Column="0" Text="设备名称" />
<TextBox Grid.Row="0" Grid.Column="1" Text="PLC-01" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="IP 地址" />
<TextBox Grid.Row="1" Grid.Column="1" Text="192.168.1.10" />
</Grid>运行结果或界面效果:
标签和输入框整齐对齐改动任务: 增加端口一行。
专项例子 3:横向状态卡
<StackPanel Orientation="Horizontal" Spacing="16" Margin="20">
<Border Padding="16" Background="#E8F5E9"><TextBlock Text="在线 3" /></Border>
<Border Padding="16" Background="#FFF3E0"><TextBlock Text="报警 1" /></Border>
<Border Padding="16" Background="#ECEFF1"><TextBlock Text="离线 2" /></Border>
</StackPanel>运行结果或界面效果:
三个状态卡横向排列改动任务: 增加“维护 1”状态卡。
第四部分:作业完整答案
这一部分给出当天作业的完整答案。先照第三部分敲一遍,再用这里检查自己的窗口结构。
作业要求
做一个静态的商品管理布局,不需要点击功能,不需要数据绑定。
页面必须包含:
- 顶部标题:
商品管理。 - 左侧商品列表:至少三个商品。
- 右侧详情区域:名称、价格两个输入框。
- 右侧底部按钮:保存、取消。
- 页面四周要有外边距,左右区域之间要有间距。
拆解步骤
- 先写最外层
Window。 - 在
Window里放一个外层Grid。 - 外层
Grid分两行:标题行和内容行。 - 外层
Grid分两列:左侧列表和右侧详情。 - 标题用
Grid.ColumnSpan="2"横跨两列。 - 左侧用
Border包住ListBox。 - 右侧用
Border包住一个内部Grid。 - 内部
Grid用两列对齐标签和输入框。 - 按钮用横向
StackPanel排列。
MainWindow.axaml 完整答案
把下面内容完整放到 Views/MainWindow.axaml。
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ProductApp.Views.MainWindow"
Width="760"
Height="460"
Title="商品管理布局练习">
<Grid RowDefinitions="Auto,*"
ColumnDefinitions="220,*"
RowSpacing="12"
ColumnSpacing="16"
Margin="16">
<TextBlock Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Text="商品管理"
FontSize="24"
FontWeight="Bold" />
<Border Grid.Row="1"
Grid.Column="0"
BorderBrush="#DDDDDD"
BorderThickness="1"
Padding="12">
<StackPanel Spacing="8">
<TextBlock Text="商品列表"
FontWeight="Bold" />
<ListBox>
<ListBoxItem Content="Keyboard" />
<ListBoxItem Content="Mouse" />
<ListBoxItem Content="Monitor" />
</ListBox>
</StackPanel>
</Border>
<Border Grid.Row="1"
Grid.Column="1"
BorderBrush="#DDDDDD"
BorderThickness="1"
Padding="16">
<Grid RowDefinitions="Auto,Auto,Auto,Auto,*"
ColumnDefinitions="Auto,*"
RowSpacing="10"
ColumnSpacing="12">
<TextBlock Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Text="商品详情"
FontSize="18"
FontWeight="Bold" />
<TextBlock Grid.Row="1"
Grid.Column="0"
Text="名称"
VerticalAlignment="Center" />
<TextBox Grid.Row="1"
Grid.Column="1"
Text="Keyboard" />
<TextBlock Grid.Row="2"
Grid.Column="0"
Text="价格"
VerticalAlignment="Center" />
<TextBox Grid.Row="2"
Grid.Column="1"
Text="199" />
<StackPanel Grid.Row="3"
Grid.Column="1"
Orientation="Horizontal"
Spacing="8"
HorizontalAlignment="Right">
<Button Content="保存" />
<Button Content="取消" />
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>运行后应该看到什么
- 窗口顶部显示
商品管理。 - 左侧区域有边框,里面是
Keyboard、Mouse、Monitor。 - 右侧区域有边框,里面有
名称和价格两行输入框。 保存和取消按钮在输入框区域下方,并且横向排列。
如果显示不对,按这个顺序检查
- 如果窗口打不开,先检查
Window的开始标签和结束标签是否都在。 - 如果控件叠在一起,检查每个控件的
Grid.Row和Grid.Column。 - 如果标题没有横跨两列,检查
Grid.ColumnSpan="2"。 - 如果左右区域太挤,检查外层
Grid的ColumnSpacing="16"。 - 如果边框里的内容贴边,检查
Border的Padding。
今天真正要掌握的判断方法
看到一个界面时,先不要问“按钮怎么写”。先问:
- 页面能不能拆成几块?
- 哪些块是上下关系?
- 哪些块是左右关系?
- 哪些块固定大小?
- 哪些块占剩余空间?
能按这五个问题拆页面,后面写 Avalonia 界面会稳定很多。