WPF布局原则
- 一个窗口中只能包含一个顶级元素。
- 不应显式设置元素尺寸。
- 不应使用坐标设置元素的位置(实际开发过程中只能说是尽量不使用了) 。
- 可以嵌套布局容器。
WPF布局容器简介
StackPanel
: 水平或垂直排列元素、Orientation
属性分别: Horizontal
/ Vertical
。
WrapPanel
: 水平或垂直排列元素、针对剩余空间不足会进行换行或换列进行排列。
DockPanel
: 根据容器的边界、元素进行Dock.Top
、Left
、Right
、Bottom
设置。
Grid
: 类似table表格、可灵活设置行列并放置控件元素、比较常用。
Border
:带边框的布局控件。
Canvas
: 使用固定的坐标设置元素的位置、不具备锚定停靠等功能。
Grid
Grid
是WPF中最为强大的布局控件,必须掌握,其可以将窗体分割成表格一样,通过行、列来进行布局。
Grid.RowDefinitions
/Grid.ColumnDefinitions
用于给Grid
分配行与列。
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
常用属性
ShowGridLines
:是否显示表格线,默认为false
。
UseLayoutRounding
:有时候由于格子分布宽度或高度不足出现非整数像素,导致图形边缘模糊,此时可以将此属性置为true
来消除模糊。
Grid.Column
和Grid.Row
:这两个属性是Grid
中的其他子控件中使用的,用来设子控件在整个Grid中的位置。
- 下标从0开始,默认就是0行0列,即第一行第一列。
<Grid>
......
<Button Content="LeftTop" Grid.Column="0" Grid.Row="0"/>
</Grid>
Grid.ColumnSpan
和Grid.RowSpan
:Grid
的子控件中使用,用来设置跨行或跨列的个数。
<Grid>
......
<Button Content="RightTop" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2"/>
</Grid>
尺寸设置
Grid`行和列的尺寸默认情况下是按同比例分配的,可以通过三种常见的设置方式:
- 通过数值进行绝对设置(不推荐),如
witdh=200
。 - 通过
Auto
来进行自动设置,其行列会根据里面的子控件的内容大小来自动设置大小,如width="auto"
。 - 使用通配符
*
按比例分配,会将设置后的所有*
相加,然后将行或列除去已经被占用的空间(没有使用*
的其他行或列)后剩下的空间按比例分配。例如width="*"
、width="2*"
、width="3*"
、width="20"
,假设Grid
的总宽度为100,那么就是100-20=80,然后将80分为6份,各自占有1份、两份和三份。
除了上面三种常用设置外,还可以在RowDefinition
或ColumnDefinition
元素中通过SharedSizeGroup="GroupName"
属性使用尺寸族来进行尺寸共享。
- 使用时,要在父类的
Grid
标签中设置<Grid.IsSharedSizeScope>true</Grid.IsSharedSizeScope>
,打开共享尺寸区域。
<Window ......>
<Grid Grid.IsSharedSizeScope="True">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="5"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" SharedSizeGroup="TestGroup"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label>只是做个小测试我这里比较长</Label>
</Grid>
<Grid Grid.Row="2" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="TestGroup"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Content="short"></Label>
</Grid>
</Grid>
</Window>
分割器-GridSplitter
GridSplitter
是在Grid
容器中使用的分割器,可以通过滑动来控制Grid
行列的长或宽。
- 注意,
GridSplitter
只能使用在Grid
中,如果希望横向分割上下滑动,需要设置其HorizontalAlignment="Stretch"
即横向填充以及VerticalAlignment="Center"
水平居中,希望纵向切割左右滑动亦然。
<Window ......>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="LeftTop" Grid.Column="0" Grid.Row="0"/>
<Button Content="RightTop" Grid.Column="1" Grid.Row="0"/>
<GridSplitter Grid.Row="1" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="5" ></GridSplitter>
<Button Content="RightTop" Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2"/>
</Grid>
</Window>
StackPanal
StackPanel
也称为堆栈面板,主要用于垂直或水平排列元素、在容器的可用尺寸内放置有限个元素,元素的尺寸总和(长/高)不允许超过StackPanel
的尺寸, 否则超出的部分不可见。
- 在
StackPanel
中的控件会根据StackPanel
的排列方向进行自适应填充。
常用属性
Orientation
:设置布局方向,可以设为Horizontal
(水平)或Vertical
(垂直)。默认为Vertical
。
HorizontalAlignment
:子元素的水平放置方式。
VerticalAlignment
:子元素的垂直放置方式。
<Window ......>
<StackPanel Name="stackPanel1" Margin="100 100 100 100" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Button1" Margin="20 20 20 20"/>
<Button Content="Button2" Margin="20 20 20 20"/>
<Button Content="Button3" Margin="20 20 20 20"/>
<Button Content="Button4" Margin="20 20 20 20"/>
<Button Content="Button5" Margin="20 20 20 20"/>
<Button Content="Button6" Margin="20 20 20 20"/>
</StackPanel>
</Window>
WrapPanel
WrapPanel
在StackPanel
功能的基础上具备在尺寸变更后自动适应容器的宽高进行换行换列处理,是唯一一个不能被Grid
取代的布局控件。
- 与
StackPanel
相反、WrapPanel
的Orientation
默认为Horizontal
。 - 在
WrapPanel
中的控件不会根据其排列方向进行自适应填充,会保持原有的默认大小。
常用属性
Orientation
:设置布局方向,可以设为Horizontal
(水平)或Vertical
(垂直)。默认为Vertical
。
HorizontalAlignment
:子元素的水平放置方式。
VerticalAlignment
:子元素的垂直放置方式。
<Window ......>
<WrapPanel Margin="100 100 100 100" VerticalAlignment="Center">
<Button Content="Button1" Margin="20 20 20 20"/>
<Button Content="Button1" Margin="20 20 20 20"/>
<Button Content="Button1" Margin="20 20 20 20"/>
<Button Content="Button1" Margin="20 20 20 20"/>
<Button Content="Button1" Margin="20 20 20 20"/>
<Button Content="Button1" Margin="20 20 20 20"/>
<Button Content="Button1" Margin="20 20 20 20"/>
</WrapPanel>
</Window>
DockPanel
DockPanel
控件对象有附加依赖属性DockPanel.Dock
, 该属性有效值为: Top
、Left
、Right
、Bottom
。默认为Left
。
- 子元素可以通过
DockPanel.Dock
属性搭配子元素在控件中的排序,来设置在容器中的展示位置和方式,千变万化,可以细细体会。
常用属性
LastChildFill
:该属性默认为true
,容器中的最后一个元素填充DockPanel
所有空间。
<Window ......>
<DockPanel >
<Button Content="Buttonleft" DockPanel.Dock="Left"/>
<Button Content="ButtonRight" DockPanel.Dock="Right"/>
<Button Content="ButtonTop" DockPanel.Dock="Top"/>
<Button Content="ButtonBottom" DockPanel.Dock="Bottom"/>
<Button Content="ButtonCenter"/>
</DockPanel>
</Window>
Border
Border
是一个带有边框的布局控件,需要注意的是Border
内只能有一个子元素。 若要显示多个子元素,需要在其中放置容器(Panel
或StackPanel
等)控件, 然后再在容器控件中进行布局。
常用属性
BorderBrush
:设置边框颜色。
BorderThickness
:设置边框粗细。
Background
:设置背景颜色。
CornerRadius
:边框四个角的弧度。
<Window ......>
<Border BorderBrush="Black" BorderThickness="1" Background="Transparent" Margin="10 10 10 10" Padding="20 20 20 20" CornerRadius="30">
<StackPanel Name="stackPanel1" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Button1" Margin="20 20 20 20"/>
<Button Content="Button2" Margin="20 20 20 20"/>
<Button Content="Button3" Margin="20 20 20 20"/>
<Button Content="Button4" Margin="20 20 20 20"/>
<Button Content="Button5" Margin="20 20 20 20"/>
<Button Content="Button6" Margin="20 20 20 20"/>
</StackPanel>
</Border>
</Window>
UniformGrid
UniformGrid
布局空间的特性在于可以自动为子控件设置行和列,默认情况下,会根据子控件的数量设置同样数量的行和列,例如当有四个Button
子控件,则分割为2行2列;当有五个Button
子控件,由于2行2列放不下,因此同时增加1行1列,因此分割为3行3列。
<Window x:Class="WPFStudy.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"
mc:Ignorable="d"
xmlns:local="clr-namespace:WPFStudy"
Title="MainWindow" Height="450" Width="800">
<UniformGrid>
<Button Content="button1"/>
<Button Content="button2"/>
<Button Content="button3"/>
<Button Content="button4"/>
<Button Content="button5"/>
</UniformGrid>
</Window>
常用属性
Rows
、Columns
:设置控件的行和列,然后子控件按序排列,当子控件数量超出所设定的行列时不显示。
Canvas
Canvas
控件通过从窗体左上角为原点的X、Y坐标(默认)来给子控件进行定位,用的较少。
常用属性
Canvas.Bottom
、Canvas.Left
、Canvas.Right
、Canvas.Top
:子控件通过这四个属性来设置自己的坐标,其中Top
的优先级高于Bottom
,Left
的优先级高于Right
。
Canvas
在C#中设置子控件的位置
在C#中直接对Canvas
中的子控件对象进行设置时,是无法直接通过Canvas.Top
这样的方式去设置子控件在Canvas
中的位置的,此时需要使用如下几个静态方法:
Canvas.SetBottom(UIElement element, double length)
Canvas.SetLeft(UIElement element, double length)
Canvas.SetRight(UIElement element, double length)
Canvas.SetTop(UIElement element, double length)
InkCanvas
InkCanvas
的布局方式与Canvas
相同,但是InkCanvas
控件可以通过一些属性来设置一些特殊的功能,达到与用户进行交互的效果。
常用属性
EditingMode
:设置容器的编辑模式。
-
Ink
:可以在容器中笔画,可以用于签名、绘画等场景。<Window x:Class="WPFStudy.Share" 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:WPFStudy" mc:Ignorable="d" Title="Share" Height="450" Width="800"> <InkCanvas EditingMode="Ink"> </InkCanvas> </Window>
Select
:可以圈中或选中控件进行移动。GestureOnly
:配合手势操作,类似于手机的手势操作,需要触控屏配合。
Strokes
:设置或获取控件中的墨迹,一般通过代码来使用。
StrokeCollection player1;
void InitializePlayersCanvases()
{
player1 = inkCanvas1.Strokes;
}
DefaultDrawingAttributes
:设置笔画的样式。
<InkCanvas EditingMode="Ink">
<InkCanvas.DefaultDrawingAttributes>
<DrawingAttributes Color="Red" Width="10" Height="10"/>
</InkCanvas.DefaultDrawingAttributes>
......
</InkCanvas>