界面布局
布局原则
不用显式的方式定义元素的尺寸。元素的尺寸尽量不要写死,这样可能更好的满足响应式,例如一下一个例子,我们有个国际化的需求,要求用户名中英文双语展示。如果一开始将用户名的长度设置成100时,用户名展示正常,似乎也没有什么问题。
现在将用户名改为国际化的username时,就会发现用户名展示不全的问题,这就是布局显式写死出现的问题。
如果未下写死的话,那么用户名就可以根据元素内容的实际长度来扩大缩小元素大小
布局控件
grid
可以将窗口按指定行和指定列进行切分,RowDefinitions 用于划分行,RowDefinitions中每一个RowDefinition表示一行,ColumnDefinitions表示列,ColumnDefinitions中每一个ColumnDefinition元素表示一列。
<Grid>
<Grid.RowDefinitions >
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions >
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
如上代码就创建了4行4列。
还可以根据占比来设置指定行或列的高度宽度,如下所示
将列平均分为1 + 1 + 1 + 3 = 6块,然后前三列每行占一块,最后一列占3块。
<Grid.RowDefinitions >
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
设置后的展示效果如下图所示,最后一列明显是前三列的三倍。
如果长宽为auto的话,那么格子里的元素最大长宽是多少,那么这个就是多少。如下所示,将第一列设置auto后,按钮001设置宽为30,在单元格中会自动将格子撑开到30.
<Grid.RowDefinitions >
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions >
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Content="按钮001" Height="30" Grid.Row="0" />
也可以设置一个最小的宽带长度,如果大于这个最小的量那么就会被撑开,如果小于那么单元格大小就是这个最小的量。
如果想要指定元素放到指定格子中可以使用以下属性来指定
Grid.Column: 行
Grid.Row: 列
如果不填默认为0
如果想要放到第一行第一列可以使用以下代码,按钮就会显示在第一行第一列,如下图所示
<Button Content="123" Grid.Column="1" Grid.Row="1"/>
可以设置元素跨行跨列多少个,如下所示将元素的 Grid.ColumnSpan和Grid.RowSpan都是设置成2,那么可以看到button元素行和宽各占了两个单元格
<Button Content="123" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" Grid.RowSpan="2"/>
StackPanel
可以将StackPanel中的元素按顺序从上到下或者从左到右进行排序
Orientation: 排序方式
- Vertical: 从上到下
- Horizontal: 从左到右
如下所示,如果我们将Orientation设置为Horizontal,那么就可以看到两个元素从左到右进行排序,如果未设置高度,那么默认占用整个高
<StackPanel Orientation="Horizontal" >
<TextBlock Text="用户名:" />
<TextBox Width="157" />
</StackPanel>
如果设置为Horizontal,那么就变成了从上到下排序了,和Horizontal一样,如果未设置宽度,那么默认占用整个宽度,如下图所示
<StackPanel Orientation="Vertical" >
<TextBlock Text="用户名:" />
<TextBox />
</StackPanel>
StackPanel可以用来做工具栏,如下图所示,使用StackPanel从左到右排序即可。
DockPanel
用于设置DockPanel中的排列停靠位置
DockPanel属性:
- LastChildFill: 最后一个元素是否填充剩余所有空间
DockPanel下元素属性:
- DockPanel.Dock: 元素在DockPanel的停靠位置
- Left: 左
- Botton: 右
- Top: 头
- Right: 右
如下图所示,我想要创建一个按下面布局的管理页面,可以直接将元素停靠在指定位置即可。
<DockPanel LastChildFill="True">
<Border Height="30" Background="Aquamarine" DockPanel.Dock="Top" />
<Border Width="50" Background="BlanchedAlmond" DockPanel.Dock="Left" />
<Border Height="50" Background="BurlyWood" DockPanel.Dock="Bottom" />
<Border Width="50" Background="Gainsboro" DockPanel.Dock="Right" />
<Border Background="Salmon" DockPanel.Dock="Bottom" />
</DockPanel>
需要注意的是需要指定元素的高度宽度才能停靠到指定位置,不然的话元素会占用所有空间。
还有要注意的是元素填充需要指定顺序,先到先得,如果下图所示,下面的border和右边的border替换顺序后它们的占用空间也会发送变化
右边的border在下面的border前设置会占用整个宽
<DockPanel LastChildFill="True">
<Border Height="30" Background="Aquamarine" DockPanel.Dock="Top" />
<Border Width="50" Background="BlanchedAlmond" DockPanel.Dock="Left" />
<Border Width="50" Background="Gainsboro" DockPanel.Dock="Right" />
<Border Height="50" Background="BurlyWood" DockPanel.Dock="Bottom" />
<Border Background="Salmon" DockPanel.Dock="Bottom" />
</DockPanel>
如果调换顺序的话,那么下面的border则会占用右边border的宽
<DockPanel LastChildFill="True">
<Border Height="30" Background="Aquamarine" DockPanel.Dock="Top" />
<Border Width="50" Background="BlanchedAlmond" DockPanel.Dock="Left" />
<Border Height="50" Background="BurlyWood" DockPanel.Dock="Bottom" />
<Border Width="50" Background="Gainsboro" DockPanel.Dock="Right" />
<Border Background="Salmon" DockPanel.Dock="Bottom" />
</DockPanel>
WrapPanel
可以按顺序从左往右排列或者从上往下排列,如果在进行排列时尺寸不够了,那么会进行换行
- Orientation: 排列属性
- Horizontal: 从左往右
- Vertical: 从上到下、
如下代码所示,我们在一个WrapPanel中新建了一批按钮列表,当第8个按钮放不下时,会自动换行放到第二行。
<WrapPanel Orientation="Horizontal" >
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
<Button Content="123" Width="100" />
</WrapPanel>
UniformGrid
可以自动生成活指定一行行列数
- Columns: 行
- Rows: 列
如果不指定行列,那么会自动按规则平均划分行列的,如下图所示,有16个按钮就会自动生成一个四行四列的表格
<UniformGrid>
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
<Button Height="100" Content="button" />
</UniformGrid>
也可以指定每行和列要展示多少个元素,如下所示,指定2*5的顺序进行排列
<UniformGrid Columns="2" Rows="5">
<Button />
<Button />
<Button />
<Button />
<Button />
<Button />
<Button />
<Button />
<Button />
</UniformGrid>
需要注意的是,如果指定的格子小于我们的元素数的话是会有部分元素无法展示的,
如下所示,我们设置的是2*2四个格子,在展示的时候只能展示4个格子,其余5个就没办法展示出来了
<UniformGrid Columns="2" Rows="2">
<Button />
<Button />
<Button />
<Button />
<Button />
<Button />
<Button />
<Button />
<Button />
</UniformGrid>
Canvas
Canvas可以将元素设置到指定位置中指定位置中,如果不设置的话就是固定在0中,如下所示,在canvas中设置了三个button,但是他们都重合在了一起:
<Canvas>
<Button Content="btn1" />
<Button Content="btn2" />
<Button Content="btn3" />
</Canvas>
可以使用Canvas.Bottom、Canvas.left、Canvas.right、Canvas.top来设置元素要设置到什么位置中,这个和margin类似,如果Canvas.top等于20的话,那么就是上空20个然后展示元素,其他也是一样,如下所示,在按钮中设置了 Canvas.Top="20" Canvas.Left="20"就会自动从上到下和从左到右各空20个空间。
<Canvas>
<Button Content="btn1" Canvas.Top="20" Canvas.Left="20" />
<Button Content="btn2" />
<Button Content="btn3" />
</Canvas>
InkCanvas
画板组件,可以在区域中进行画画或者选择组件拖动放大等功能。其他的top、left、right、bottom功能和Canvas一样不同的是组件前缀是InkCanvas.而不是Canvas.
EditingMode: 画笔模式
- Ink: 画笔,可以在组件上画画
- Select: 选择移动元素
- EraseByStroke: 整笔擦除
- EraseByPoint: 橡皮擦除
Ink画笔,如下所示:
<Grid>
<InkCanvas EditingMode="Ink" >
<Button Content="btn01" />
<Button Content="btn01" />
<Button Content="btn01" />
<Button Content="btn01" />
</InkCanvas>
</Grid>
Border
装饰控件,块元素,用于绘制边框,例如边框圆角,边框颜色等等。
属性:
- BorderThickness: 变宽宽度
- BorderBrush: 边框颜色
- CornerRadius: 圆角程度
如下代码所示,我grid创建了一个边框粗细为5,边框颜色为黑色,圆角为50单位的边框。
<Border BorderThickness="5" BorderBrush="Black" Margin="5" CornerRadius="50" >
<Grid>
</Grid>
</Border>