前言
本文本来是在WPF桌面端开发1中写过的,但是随着篇幅越来越长,就单独拆出来了。
静态容器
- Canvas布局 绝对定位
- StackPanel 行列布局不能换行
- WrapPanel 行列布局能换行
- DockPanel 东西南北布局
- Grid 网格布局 最强大的布局
- UniformGrid 简化网格布局 等分布局
Canvas布局
Canvas是一个类似于坐标系的面板,所有的元素通过设置坐标来决定其在坐标系中的位置。具体表现为使用Left、Top、Right、 Bottom附加属性在Canvas中定位控件。
相同位置的元素后面的居上
1 | <Canvas> |
StackPanel布局
StackPanel将控件按照行或列来顺序排列,但不会换行。通过设置面板的Orientation属性设置了两种排列方式:横排(Horizontal默认的)和竖排(Vertical),默认为竖排(Vertical)。
1 | <StackPanel Name="stackpanel3" Orientation="Horizontal" FlowDirection="RightToLeft"> |
WrapPanel布局
WrapPanel布局面板将各个控件按照一定方向罗列,当长度或高度不够时自动调整进行换行换列。
Orientation=”Horizontal”时各控件从左至右罗列,当面板长度不够时,子控件就会自动换行,继续按照从左至右的顺序排列。
Orientation=”Vertical”时各控件从上至下罗列,当面板高度不够时,子控件就会自动换列,继续按照从上至下的顺序排列。
1 | <WrapPanel Orientation="Horizontal"> |
DockPanel布局
DockPanel支持让元素简单地停靠在整个面板的某一条边上,然后拉伸元素以填满全部宽度或高度。它也支持让一个元素填充其他已停靠元素没有占用的剩余空间。
DockPanel有一个Dock附加属性,因此子元素用4个值来控制她们的停靠:Left、Top、Right、Bottom。Dock没有Fill值。作为替代,最后的子元素将加入一个DockPanel并填满所有剩余的空间,除非DockPanel的LastChildFill属性为false,它将朝某个方向停靠。
1 | <DockPanel> |
设置LastChildFill属性为false
1 | <DockPanel LastChildFill="False"> |
Grid布局
功能最强大的布局。
默认情况下,Grid的子元素会自动调整大小占满其所在单元格。你通常不需要为其设置大小,它的大小会根据所在单元格变化而与单元格保持一致。
你也可以通过设置子元素的Margin 属性来设定其与单元格边距距离。
Grid允许我们通过自定义行列来进行布局,这类似于表格.通过定义Grid的RowDifinitions
和ColumnDifinitions
来实现对于表格行和列的定义
元素根据附加属性Grid.Row
和Grid.Column
确定自己的位置。
Grid的列宽与行高可采用固定、自动、按比列三种方式定义
- 固定长度——值为一个确定的数字
- 自动长度——值为
Auto
,实际作用就是取实际控件所需的最小值 - 比例长度——
*
表示占用剩余的全部宽度;两行都是*
,将平分剩余宽度;一个2*
,一个*
,则前者占剩余全部宽度的2/3
,后者占1/3
;依此类推
1 | <Grid> |
UniformGrid布局
局限较大,只适合等分的情况。
UniformGrid就是Grid的简化版,每个单元格的大小相同,不需要定义行列集合。每个单元格始终具有相同的大小,每个单元格只能容纳一个控件。
若不设置Rows/Colums,则按照定义在其内部的元素个数,自动创建行列,并通常保持相同的行列数。
若只设置Rows则固定行数,自动扩展列数。
若只设置Colums则固定列数,自动扩展行数。
UniformGrid 中没有Row和Column附加属性,也没有空白单元格。
1 | <UniformGrid> |
如果设置列数 行高会均分
1 | <UniformGrid Margin="16,0,16,0" Columns="1"> |
动态容器
- ItemsControl
- ListBox
- ListView
- DataGrid
ItemsControl、ListBox和ListView
ItemsControl
=>ListBox
=>ListView
ListView继承于ListBox,ListBox继承于ItemsControl,所以后面的组件拥有前面组件的一切特性。
相同点:
这三个控件都是列表型控件,可以进行列表绑定(ItemsSource);
这三个控件均使用ItemsPresenter来展示列表信息;
不同点:
ItemsControl是不包含水平和垂直方向的滚动条的。ListBox和ListView有水平和垂直方向滚动条。
ListBox 继承于ItemsControl,增加了一个Selector对象,ItemsControl中的Item是不支持选择的。
而ListBox中Item是支持选择,并且可以单选,多选。
ListView类似 Gridview ,支持多列
ListBox很简单, 就一列
ListView和DataGrid
- ListView 理解为只读控件,更像是一种View(视图),而DataGrid更倾向于编辑数据。
- DataGrid允许自动生成列,ListView不行。
- DataGrid有RowDetails元素, ListView没有。
- DataGrid支持所有ListView支持的东西。
ListBox
水平方向填满
ListView
其实就是表格组件,ItemsControl
不支持内容滚动,所以我们最常用的就是ListBox
.
模板和样式
1 | <Window.Resources> |
页面中使用
1 | <ListBox |
行内样式和单独样式对比
1 | <ListBox> |
等同于
1 | <ListBox ItemContainerStyle="{StaticResource ListBoxItemStyle}"> |
以及
1 | <Window.Resources> |
修改选中样式
1 | <ListBox |
滚动条设置
1 | ScrollViewer.HorizontalScrollBarVisibility="Disabled" |
全局样式
StyleListBoxItem.xaml
1 | <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
OverwrideDefaultControlStyles.xaml
1 | <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
注意
这里这样配置会全局生效,可以把第7行删掉,使用下面的方式引用
Application
1 | <Application.Resources> |
使用
1 | <ListBox |
ListView
就是类似网页中的表格
1 | <ListView x:Name="listView1" |
结论
该组件不常用,主要原因是样式不太好调
如果做后台管理可以考虑,前端展示还是别用了。
单双行变色
方法1
定义使用 IValueConverter 来使背景色产生交替效果的样式
下面的示例显示依据行索引设置 Background 属性的 IValueConverter 的定义。
C#
1 | public sealed class BackgroundConverter : IValueConverter |
样式
1 | <Style x:Key="myItemStyle" TargetType="{x:Type ListViewItem}"> |
下面的示例为 IValueConverter 定义 ResourceKey。
XAML
1 | <namespc:BackgroundConverter x:Key="myConverter"/> |
下面的示例演示如何定义使用 Style 作为其 ItemContainerStyle 以便提供所需布局的 ListView。
XAML
1 | <ListView Name="theListView" |
方法2
从 ListView 中派生一个新类以使背景色产生交替效果
1 | public class SubListView : ListView |
XAML
1 | <namespc:SubListView |
方法3
使用 StyleSelector 使背景色产生交替效果
下面的示例演示如何定义一个为行定义 Style 的 StyleSelector。此示例依据行索引定义 Background 颜色。
C#
1 | public class ListViewItemStyleSelector : StyleSelector |
下面的示例演示如何为 StyleSelector 定义 ResourceKey。namespc 前缀映射到 CLR 命名空间和其中定义了 StyleSelector 的对应程序集。有关更多信息,请参见 XAML 命名空间和命名空间映射。
XAML 复制代码
1 | <namespc:ListViewItemStyleSelector x:Key="myStyleSelector"/> |
下面的示例演示如何将 ListView 的 ItemContainerStyleSelector 属性设置为此 StyleSelector 资源。
XAML
1 | <ListView |
在 ListViewItem 集合中进行更改后更新 ListView
如果从 ListView 控件中添加或移除 ListViewItem,您必须更新 ListViewItem 控件以便重新创建交替的 Background 颜色。下面的示例演示如何更新 ListViewItem 控件。
C#
1 | ICollectionView dataView = |
单子组件容器
ScrollViewer布局
ScrollViewer是带有滚动条的面板。在ScrollViewer中只能有一个子控件,若要显示多个子控件,需要将一个附加的 Panel控件放置在父 ScrollViewer中。然后可以将子控件放置在该控件中。
HorizontalScrollBarVisibility水平滚动条是否显示默认为Hidden
VerticalScrollBarVisibility垂直滚动条是否显示 默认为Visible。
一般我们都会设置 HorizontalScrollBarVisibility=”Auto” VerticalScrollBarVisibility=”Auto”
意思是:当内容超出可视范围时,才显示横向/纵向滚动条
1 | <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> |
ViewBox布局
https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.controls.viewbox?view=netframework-4.8
Viewbox的作用是拉伸或延展位于其中的组件,以填满可用空间。在Viewbox中只能有一个子控件,若要显示多个子控件,需要将一个附加的Panel控件放置在父Viewbox中。然后可以将子控件放置在该控件中。
常用属性:
Stretch:获取或设置拉伸模式以决定该组件中的内容以怎样的形式填充该组件的已有空间。具体设置值如下:
值 | 作用 | |
---|---|---|
None | 不进行拉伸,按子元素设置的长宽显示 | |
Uniform | 按原比例缩放子元素,使得一边不足,另一边恰好填充 | |
Fill | 缩放子元素,使得子元素的长变为Viewbox的长,宽变为Viewbox的宽 | |
UniformToFill | 按原比例缩放子元素,使得子元素一边恰好填充,另一边超出Viewbox的区域 |
StretchDirection:获取或设置该组件的拉伸方向以决定该组件中的内容将以何种形式被延展。具体的设置值如下。
值 | 作用 |
---|---|
Both | 内容将根据 Stretch 模式进行拉伸以适应父级。 |
DownOnly | 内容仅在大于父级时缩放。 如果内容较小,则不会执行任何扩展。 |
UpOnly | 内容仅在小于父级时扩展。 如果内容较大,则不执行缩放。 |
Stretch默认值为Uniform
。
1 | <Viewbox Grid.Row="0" Grid.Column="1" Stretch="Uniform"> |
注意Stretch默认值为
Uniform`
假如我们按如下设置
1 | <Viewbox Width="200" Height="200"> |
那么实际结果Viewbox的尺寸是
也就是说Viewbox设置的宽高只代表我占个多大的地,实际渲染的时候会根据子组件的宽高变化。
Border
Border 是一个装饰的控件,此控件用于绘制边框及背景,在Border中只能有一个子控件,若要显示多个子控件,需要将一个附加的Panel控件放置在父Border中。然后可以将子控件放置在该 Panel控件中。
常用属性:
Background: 背景色 ;
BorderBrush: 边框色 ;
BorderThickness: 边框宽度;
CornerRadius: 各个角 圆的半径;
1 | <Border Background="YellowGreen" BorderBrush="Black" BorderThickness="0, 2, 4, 6" CornerRadius="0, 10, 20, 30"> |
设置阴影
1 | <views:ZJClippingBorder |
其中
要设置Margin值让边缘的阴影不被裁剪。
内部元素会变模糊,建议阴影的这一层放下面,把内部的放在上一层。
SnapsToDevicePixels和UseLayoutRounding均是解决边缘模糊的问题
SnapsToDevicePixels是在during rendering的时候生效的
UseLayoutRounding是在during layout的时候生效的
默认的Border不能剪切内部元素,自定义border支持内部剪切
1 | using System; |
定位常用属性
在设计UI时,WPF为我们提供了一些属性用于精确定位元素
其中最常用的有三个:Alignment(包括水平,垂直),Margin,Padding,
具体用法如下:
HorizontalAlignment: 子元素在水平方向的对齐方式,有左对齐,右对齐,中间对齐,拉伸填充等四种方式。
VerticalAlignment:子元素在垂直方向的对齐方式,有顶端对齐,底部对齐,中间对齐,拉伸填充等四种方式。
Margin:用于指定元素与其父级或同级之间的距离,包括上下左右四个值。也可通过使用 Margin=”20”同时指定四个值。
Padding:用于指定元素与其子级之间的距离,包括上下左右四个值。也可通过使用Padding=”20”同时指定四个值。
内容定位
1 | VerticalContentAlignment="Center" |