WPF学习笔记03-布局Layout

WPF相对于Winform而言,在WPF中是用不同的容器安排布局。每个容器都有各自的布局逻辑,有的以堆栈方式布置有的以单元格排列元素。这也是WPF中比较有意思的,更容易入门。通过了解WPF布局之后能有个大概的WPF乐趣之处。

1 - 理解WPF中布局

区别于Winform而言,Winform中使用刻板的基于坐标的布局将控件放到正确位置。在WPF中,使用流布局(flow)。能创建与显示分辨率和窗口大小无关的,在不同显示器正确缩放。

1.1 - WPF 布局原则

WPF窗口只能包含单个元素。在窗口放置一个容器,然后在该容器中添加其他元素。

WPF中,需要遵循以下几条重要原则:

    • 不应显式设定元素尺寸。
    • 不应使用屏幕坐标指定元素位置。
    • 布局容器的子元素共享可用空间
    • 可嵌套的布局容器

WPF应该遵循这些原则,如果不遵循这些原则,最终将得到不是很适合WPF的并且难以维护的用户界面。

1.2 - 布局过程

包含两个阶段:测量和排列。

测量阶段:容器遍历所有子元素,并询问子元素他们所期望的尺寸。

排列阶段:容器在合适的位置放置子元素。

1.3 - 布局容器

所有WPF布局容器都派生于System.Windows.Controls.Panel抽象类的面板

WPF中提供了大量继承于Panel的类。这些类都位于System.Windows.Controls命名空间中

名 称

说 明

StackPanel

在水平或垂直的堆栈中放置元素。通常用于更大、更复杂窗口中的一些小区域。

WrapPanel

在一系列中可换行的行中放置元素

DockPanel

根据元素的整个边界调整元素

Grid

根据不可见的表格在行列中排列元素,也是最灵活最常用的容器之一

UniformGrid

在不可见但是强制所在单元格具有相同尺寸放置元素,不常见

Canvas

使用固定坐标绝对定位元素与Winform相似,没有提供锚定或停靠功能。

除了这些容器外,还有几个更专业的面板。如TabPanel面板、ToolbarPanel面板和VirtualizingStackPanel面板、InkCanvas控件等等。

2 - 使用StackPanel面板进行简单布局

StackPanel面板是嘴贱的布局容器之一。在单行或者单列中以堆栈方式放置其子元素。

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="200">
    <StackPanel>
        <Label Content="这个是StackPanel布局"/>
        <Button Content="第一个按钮"/>
        <Button Content="第二个按钮"/>
        <Button Content="第三个按钮"/>
        <Button Content="第四个按钮"/>
    </StackPanel>
</Window>

界面如下

默认情况下,StackPanel面板按照自上而下顺序排列元素,使每个元素的高度适合它的内容。在上个Demo中,所有元素都被拉伸到整个程序的宽度,如果加宽从窗口,StackPanel也会变宽,里边对应的元素也会拉伸自身。

Orientation属性:可以使面板水平排列元素

<StackPanel Orientation="Horizontal">

界面如下

根据窗口的当前大小可能导致一些元素不适应、

2.1 - 布局属性

名 称

说 明

HorizontalAlignment

水平方向有额外空间时,该属性决定了子元素在布局容器中如何定位,可选有Center Left Right Stretch等属性

VerticalAlignment

垂直方向有额外空间时,该属性决定了子元素在布局容器中如何定位,可选有Center Left Right Stretch等属性

Margin

设置对应边距,顺序分别为左上右下,如果两个的话为左右、上下

MinWidth和MinHeight

设置元素的最小尺寸

MaxWidth和MaxHeight

设置元素的最大尺寸

Width和Height

设置元素的尺寸,宽度和高度,不能超过设置的最大值和最小值

所有的属性都从FrameworkElement基类继承而来。所以在WPF窗口中所使用的的所有图形小组件都支持这些属性。

2.2 - 对齐方式

对齐方式可以通过下述代码来实现,对齐方式可以分为Left Right Center Stretch

<StackPanel>
    <Label HorizontalAlignment="Center" Content="这个是StackPanel布局"/>
    <Button HorizontalAlignment="Left" Content="第一个按钮"/>
    <Button HorizontalAlignment="Right" Content="第二个按钮"/>
    <Button Content="第三个按钮"/>
    <Button Content="第四个按钮"/>
</StackPanel>

界面如下

可以看到第一个元素居中,第二个元素居左,第三个元素居右。

2.3 - 边距(Margin)

当我们设置对应第四个元素的Margin属性时,可以看到对应边距

<Button Margin="10" Content="第三个按钮"/>

上下左右边距分别为10个元素

当设置为10,5时

<Button Margin="10,5" Content="第三个按钮"/>

界面如下

当设置为四个元素时

 <Button Margin="20,15,10,5" Content="第三个按钮"/>

界面如下

综上所述,当我们这只对应边距(Margin)时,可以分别设置为1,2,4时分别为:

一个时:上下左右分别为对应间距

两个时:左右为第一个、上下为第二个

四个时:分别为左上右下

2.4 - 最小尺寸、最大尺寸以及显式设置尺寸

最小尺寸设置为100时,最大尺寸设置为150时,代码和界面

<Button MinWidth="100" MaxWidth="150" Content="第四个按钮"/>

最小尺寸为每个按钮的尺寸始终不能小于最小尺寸

最大尺寸为不能超过最大尺寸

如果最小宽度大于容器宽度时,按钮一部分将被裁剪掉。否则不允许按钮比Panel面板更宽

3 - WrapPanel和DockPanel面板

3.1 - WrapPanel 面板

WrapPanel面板以一次一行或者一列方式部署控件。默认情况下,WrapPanel的Orientation属性为Horizontal,控件从左向右进行排列,再在下一行中排列。将其属性设置为Vertical,从而在多个列中放置元素。

代码和界面

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="400">
    <WrapPanel Margin="3">
        <Button VerticalAlignment="Top" Content="第一个按钮"/>
        <Button MinHeight="50" Content="第二个按钮"/>
        <Button VerticalAlignment="Bottom" Content="第三个按钮"/>
        <Button Content="第四个按钮"/>
        <Button VerticalAlignment="Center" Content="第五个按钮"/>
    </WrapPanel>
</Window>

界面如下

WrapPanel是唯一一个不能通过灵活使用Grid面板代替的容器

3.2 - DockPanel面板

DockPanel沿着一条外边缘来拉伸所包含的控件。通过对应的附加属性选择靠边,可将对应属性设置为Left,Right,Top,和Bottom。放在DockPanel面板的每个元素都会自动获取该属性。

代码和界面如下

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="400">
    <DockPanel>
        <Button DockPanel.Dock="Top" Content="上边按钮"/>
        <Button DockPanel.Dock="Left" Content="左边按钮"/>
        <Button DockPanel.Dock="Right" Content="右边按钮"/>
        <Button DockPanel.Dock="Bottom" Content="下边按钮"/>
        <Button Content="默认充满的按钮"/>
    </DockPanel>
</Window>

界面如下

如果说对应一个里边包含了多个元素可以分别设置

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="400">
    <DockPanel>
        <StackPanel DockPanel.Dock="Top">
            <Button  Content="上边按钮"/>
            <Button HorizontalAlignment="Left" Content="上边按钮2"/>
            <Button HorizontalAlignment="Right" Content="上边按钮3"/>
        </StackPanel>
        <Button DockPanel.Dock="Left" Content="左边按钮"/>
        <Button DockPanel.Dock="Right" Content="右边按钮"/>
        <Button DockPanel.Dock="Bottom" Content="下边按钮"/>
        <Button Content="默认充满的按钮"/>
    </DockPanel>
</Window>

界面如下

3.3 - 嵌套布局容器

布局容器也是可以嵌套的。如创建一个标准对话框,右下角为确认和返回按钮,并在剩余部分创建对应文字说明。

1 - 创建StackPanel,将亮哥按钮放置一块

2 - 在DockPanel放置StackPanel 并停靠下边

3 - 将DockPanel的LastChildFill设置为True

4 - 设置边距属性,提供一定的空白空间

如下代码

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="200">
    <DockPanel LastChildFill="True">
        <Border  Margin="10" DockPanel.Dock="Top" BorderBrush="Orange" BorderThickness="2" >
            <TextBlock TextWrapping="Wrap" Height="80"  Text="月明星稀,乌鹊南飞,此非曹孟德之诗乎?"/>
        </Border>
        <StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Right" Orientation="Horizontal">
            <Button Padding="3" Content="确认"/>
            <Button Padding="3" Content="取消"/>
        </StackPanel>
    </DockPanel>
</Window>

界面如下

3.4 - Grid面板

Grid是WPF中最强大的布局容器。很多使用其他完成的用Grid都可以完成。Grid是可以将面板分为几行几列的网格。Grid虽然不可见但是可以将Grid.ShowGridLines属性设置为True。方便调试。

创建Grid需要设置对应的行列,随后填充对应内容。

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="200">
    <Grid ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
    </Grid>
</Window>

界面如下

这是Grid的布局,此时我们可以开始向Grid中填充元素。比如我们向第二行第三列中添加一个显示内容为"点击我"的按钮

<Button Content="点击我" Grid.Column="2" Grid.Row="1"/>

界面如下

调整行和列

Grid面板支持三种设置尺寸的方式:

    • 绝对设置尺寸方式 如:Width=“100”
    • 自动设置尺寸方式 如:Width=“Auto”
    • 按照比例设置尺寸方式 如:Width=“*”
<Grid.RowDefinitions>
    <RowDefinition Height="*"/>
    <RowDefinition Height="1.5*"/>
    <RowDefinition Height="2.5*"/>
</Grid.RowDefinitions>

自动设置

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="200">
    <Grid ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBox Margin="10" Grid.Row="0" Text="这是一个测试的"/>
        <StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal">
            <Button Margin="10,10,2,10" Padding="3" Content="确 认"/>
            <Button Margin="2,10,10,10" Padding="3" Content="取 消"/>
        </StackPanel>
    </Grid>
</Window>

界面如下

3.5 - UniformGrid 和 Canvas面板

3.5.1 - UniformGrid面板

UniformGrid不同于Grid 不需要设置对应行列,设置简单Rows和Columns来设置尺寸即可。

比如:

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="200">
    <UniformGrid Rows="3" Columns="3">
        <Button Content="1"/>
        <Button Content="2"/>
        <Button Content="3"/>
        <Button Content="4"/>
        <Button Content="5"/>
        <Button Content="6"/>
        <Button Content="7"/>
        <Button Content="8"/>
        <Button Content="9"/>
    </UniformGrid>
</Window>

界面如下

3.5.2 - Canvas 面板

Canvas面板允许使用精确的坐标放置元素。需要设置Canvas.Left和Canvas.Top附加属性,Left属性设置元素左边和Canvas面板左边之间的单位数。从左上角(0,0)开始到右下角分别为X,Y。

如下代码:

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="240">
    <Canvas>
        <Button Canvas.Left="10" Canvas.Top="10" Content="(10,10)"/>
        <Button Canvas.Left="40" Canvas.Top="60" Content="(40,60)"/>
        <Button Canvas.Left="100" Canvas.Top="20" Content="(100,20)"/>
        <Button Canvas.Left="140" Canvas.Top="90" Content="(140,90)"/>
    </Canvas>
</Window>

界面如下:

按照画布的坐标点布局。

其中Z顺序

<Button Canvas.Left="10" Panel.ZIndex="0" Canvas.Top="10" Content="(10,10)1"/>
<Button Canvas.Left="10" Panel.ZIndex="1" Canvas.Top="10" Content="(10,10)2"/>

同样的坐标体系,当ZIndex较大时,才会显示在最顶层。当设置第一个元素的ZIndex为2时,界面显示的名称是“(10,10)1”

3.6 - 布局Demo

行列设置:

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="300">
    <Grid Margin="10,3,10,10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <!--第一行-->
        <Label Grid.Row="0" Grid.Column="0" Margin="3" Content="主页:" VerticalAlignment="Center"/>
        <TextBox Grid.Row="0" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"/>
        <Button Grid.Column="2" Grid.Row="0" Content="选择路径" Margin="3" Padding="2" Height="Auto" VerticalAlignment="Center"/>
        <!--第二行-->
        <Label Grid.Row="1" Grid.Column="0" Margin="3" Content="系统设置表:" VerticalAlignment="Center"/>
        <TextBox Grid.Row="1" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"/>
        <Button Grid.Column="2" Grid.Row="1" Content="选择路径" Margin="3" Padding="2" Height="Auto" VerticalAlignment="Center"/>
        <!--第三行-->
        <Label Grid.Row="2" Grid.Column="0" Margin="3" Content="人员信息表:" VerticalAlignment="Center"/>
        <TextBox Grid.Row="2" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"/>
        <Button Grid.Column="2" Grid.Row="2" Content="选择路径" Margin="3" Padding="2" Height="Auto" VerticalAlignment="Center"/>
        <!--第四行-->
        <Label Grid.Row="3" Grid.Column="0" Margin="3" Content="权限信息表:" VerticalAlignment="Center"/>
        <TextBox Grid.Row="3" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"/>
        <Button Grid.Column="2" Grid.Row="3" Content="选择路径" Margin="3" Padding="2" Height="Auto" VerticalAlignment="Center"/>
    </Grid>
</Window>

界面如下:

Demo2

<Window x:Class="Demo_Layout.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:Demo_Layout"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="300">
    <Grid Margin="10,3,10,10">
        <TabControl>
            <TabItem Header="第一页">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="7*"/>
                    </Grid.RowDefinitions>
                    <StackPanel Orientation="Horizontal" Grid.Row="0">
                        <Label Content="住院号:" VerticalAlignment="Center"/>
                        <TextBox Height="Auto" HorizontalAlignment="Center" Width="150" Margin="0,5"/>
                        <Button VerticalAlignment="Center" Content="查  询" Height="Auto" Margin="5,5" Width="50"/>
                    </StackPanel>
                    <DataGrid Grid.Row="1">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="住院号" Width="80"/>
                            <DataGridTextColumn Header="姓名" Width="90"/>
                            <DataGridTextColumn Header="是否启用" Width="Auto"/>
                        </DataGrid.Columns>
                    </DataGrid>
                </Grid>
            </TabItem>
            <TabItem Header="第二页"/>
        </TabControl>
    </Grid>
</Window>

界面

posted @ 2023-03-02 13:53  IceAmos  阅读(529)  评论(0编辑  收藏  举报