布局
布局窗口的几条重要原则:
- 不应显示设定元素(控件)的尺寸。
- 不应使用屏幕坐标指定元素的位置。
- 布局容器的子元素“共享”可用空间。
- 合理嵌套布局容器。
布局的过程:
- 测量阶段Measure:容器遍历所有子元素,询问子元素他们所希望的尺寸。
- 排列阶段Arrange:容器在合适的位置放置子元素。
布局容器都派生自Panel类。
属性 | 备注 | 权限 |
---|---|---|
Background | 背景 | public |
Children | 子元素 | public |
HasLogicalOrientation | 如果 Panel 的方向是在一个维度上,则为 true ;否则为 false 。 | protected |
HasLogicalOrientationPublic | 如果 Panel 的方向是在一个维度上,则为 true ;否则为 false 。 | public |
InternalChildren | 获取子元素的 UIElementCollection。 | protected |
IsItemsHost | 如果此 Panel 实例是项宿主,则为 true ;否则为 false 。 默认值是 false 。 | public |
LogicalChildren | 获取一个枚举器,它可以循环访问此 Panel 元素的各个逻辑子元素。 | protected |
LogicalOrientation | 如果面板支持只有一个维度的布局,则为面板的 Orientation。 | protected |
LogicalOrientationPublic | 如果面板支持只有一个维度的布局,则为面板的 Orientation。 | public |
VisualChildrenCount | 获取此 Visual 实例中的子 Panel 对象数。 | protected |
方法 | 备注 | 权限 |
---|---|---|
CreateUIElementCollection | 创建一个新的 UIElementCollection。 | protected |
GetVisualChild | 获取指定索引位置处的此 Visual 的 Panel 子级 | protected |
GetZIndex | 获取给定元素的 ZIndex 属性的值。 | public |
OnIsItemsHostChanged | 指示 IsItemsHost 属性值已更改。 | protected |
OnRender | 在 Panel 元素的呈现处理过程中,绘制 DrawingContext 对象的内容。 | protected |
OnVisualChildrenChanged | 当修改可见对象的 VisualCollection 时调用。 | protected |
SetZIndex | 设置给定元素的 ZIndex 附加属性的值。 | public |
ShouldSerializeChildren | 确定是否应对面板的 Children 集合进行序列化。 | public |
附加属性 | 备注 |
ZIndex | 获取或设置一个值,该值表示元素在 Z 平面中的显示顺序 |
如果希望自定义,需要用到Panel的几个内部属性,还可能需要重新FrameworkElament类的MeasureOverride()方法和ArrangeOverride()方法。
布局属性
名称 | 布局 |
---|---|
HorizontalAlignment | 水平对齐特征 |
VerticalAlignment | 垂直对齐特征 |
Margin | 外边距 |
MaxHeight | 最大高度约束 |
MinHeight | 最小高度约束 |
Height | 高度 |
MaxWidth | 最大宽度约束 |
MinWidth | 最小宽度约束 |
Width | 宽度 |
以上均继承自FrameworkElament |
Canvas
Object->DispatcherObject->DependencyObject->Visual->UIElement->FrameworkElement->Panel->Canvas
方法 | 备注 | 权限 |
---|---|---|
ArrangeOverride | 排列 Canvas 元素的内容。 | protected |
GetBottom | 返回给定依赖对象的 Bottom 附加属性的值。 | public |
GetLayoutClip | 返回一个剪裁几何图形,它指示当 ClipToBounds 属性设置为 true 时要剪裁的区域。 | protected |
GetLeft | 为给定的依赖对象获取 Left 附加属性的值。 | public |
GetRight | 为给定的依赖对象获取 Right 附加属性的值。 | public |
GetTop | 为给定的依赖对象获取 Top 附加属性的值。 | public |
MeasureOverride | 测量 Canvas 的子元素,以便准备在 ArrangeOverride(Size) 处理过程中排列它们。 | protected |
SetBottom | 设置给定的依赖对象设置上的 Bottom 附加属性值。 | public |
SetLeft | 设置给定的依赖对象设置上的 Left 附加属性值。 | public |
SetRight | 设置给定的依赖对象设置上的 Right 附加属性值。 | public |
SetTop | 设置给定的依赖对象设置上的 Top 附加属性值。 | public |
附加属性 | 备注 |
Bottom | 获取或设置一个值,该值表示元素底部与其父 Canvas 底部之间的距离。 |
Left | 获取或设置一个值,该值表示元素左侧与其父 Canvas 左侧之间的距离。 |
Right | 获取或设置一个值,该值表示元素右侧与其父 Canvas 右侧之间的距离。 |
Top | 获取或设置一个值,该值表示元素顶部与其父 Canvas 顶部之间的距离。 |
Canvas示例
Canvas面板是基于坐标的布局。
Canvas内部是相对坐标,坐标值接受负数。这是一个坐标布局元素。
接着改变窗口尺寸:
测试2相对于左上角(Left、Top)的位置没变。
测试1相对于右下角(Bottom、Right)的位置没变。
可见当Canvas变化后,元素相对于Canvas的位置没有变化,即相对位置固定不变。
附加属性 Canvas.Top优先于Canvas.Bottom,Canvas.Left优先于Canvas.Right 。
看下列代码:
<Window x:Class="_5_UI详解.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:_5_UI详解"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Canvas Background="AliceBlue" >
<Canvas.Children >
<TextBlock
Width="100"
Height="100"
Padding="0 30"
TextAlignment="Center"
Background="Blue"
Foreground="Pink"
FontSize="24"
Text="测试1"
Canvas.Bottom="100"
Canvas.Right="100" />
<TextBlock
Width="100"
Height="100"
Padding="0 30"
TextAlignment="Center"
Background="Red"
FontSize="24"
Text="测试2"
Canvas.Left="100"
Canvas.Top="100"
Canvas.Bottom="100"
Canvas.Right="100" />
</Canvas.Children>
</Canvas>
</Grid>
</Window>
测试1: Canvas.Bottom="100"
Canvas.Right="100"
测试2: Canvas.Left="100"
Canvas.Top="100"
Canvas.Bottom="100"
Canvas.Right="100"
运行结果:
测试1和测试2赋予了相同的Bottom和Right值,但是最终显示位置却不一样。因为附加属性 Canvas.Top优先于Canvas.Bottom,Canvas.Left优先于Canvas.Right 。
UIElement.ClipToBounds对Canvas的影响:值为True时,内部元素溢出部分会被裁剪。
修改:
测试1: Canvas.Right="-30"
Canvas : Width="790" Height="400" ClipToBounds="True"
使Canas固定大小,不随Window的变化而变化。
代码如下:
<Window x:Class="_5_UI详解.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:_5_UI详解"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Canvas Background="AliceBlue" ClipToBounds="True" Width="790" Height="400">
<Canvas.Children >
<TextBlock
Width="100"
Height="100"
Padding="0 30"
TextAlignment="Center"
Background="Blue"
Foreground="Pink"
FontSize="24"
Text="测试1"
Canvas.Bottom="100"
Canvas.Right="-30" />
<TextBlock
Width="100"
Height="100"
Padding="0 30"
TextAlignment="Center"
Background="Red"
FontSize="24"
Text="测试2"
Canvas.Left="100"
Canvas.Top="100"
Canvas.Bottom="100"
Canvas.Right="100" />
</Canvas.Children>
</Canvas>
</Grid>
</Window>
ClipToBounds="True" 时,运行:
拖动放大窗口:
发现测试1被裁剪了。
ClipToBounds="False" 时,拖动放大窗口:
发现测试1未被裁剪了。
Panel.ZIndex对内部元素的影响:元素的默认ZIndex值为0,ZIndex值越大的元素,层叠越高。ZIndex值可以为正整数、负整数或0。ZIndex附加属性等同于Canvas.SetIndex方法。
使用第一部分代码,拖动缩小窗口:
测试2在测试1的上面
在测试1中加入Panel.ZIndex="1"
发现测试1在测试2的上面。
<Window x:Class="_5_UI详解.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:_5_UI详解"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Canvas Background="AliceBlue" >
<Canvas.Children >
<TextBlock
Width="100"
Height="100"
Padding="0 30"
TextAlignment="Center"
Background="Blue"
Foreground="Pink"
FontSize="24"
Text="测试1"
Canvas.Bottom="100"
Canvas.Right="100"
Panel.ZIndex="1"/>
<TextBlock
Width="100"
Height="100"
Padding="0 30"
TextAlignment="Center"
Background="Red"
FontSize="24"
Text="测试2"
Canvas.Left="100"
Canvas.Top="100"
Canvas.Bottom="100"
Canvas.Right="100"
/>
</Canvas.Children>
</Canvas>
</Grid>
</Window>
下面用C#语言创建UI
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace _5_UI详解
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.Background = Brushes.Blue;
myTextBlock1.Width = 100;
myTextBlock1.Height = 100;
myTextBlock1.Padding = new Thickness(0, 30, 0, 0);
myTextBlock1.Text = "测试11";
myTextBlock1.FontSize = 24;
myTextBlock1.Foreground = Brushes.Pink;
myTextBlock1.TextAlignment = TextAlignment.Center;
Canvas.SetBottom(myTextBlock1,100);
Canvas.SetRight(myTextBlock1, 100);
Canvas.SetZIndex(myTextBlock1, 1);
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Background = Brushes.Red;
myTextBlock2.Width = 100;
myTextBlock2.Height = 100;
myTextBlock2.Padding = new Thickness(0, 30, 0, 0);
myTextBlock2.Text = "测试22";
myTextBlock2.FontSize = 24;
myTextBlock2.TextAlignment = TextAlignment.Center;
Canvas.SetLeft(myTextBlock2, 100);
Canvas.SetTop(myTextBlock2, 100);
Canvas myCanvas = new Canvas();
myCanvas.Children.Add(myTextBlock1);
myCanvas.Children.Add(myTextBlock2);
//Grid grid = new Grid();
//grid = this.Content as Grid;
//grid.Children.Add(myCanvas);
(this.Content as Grid).Children.Add(myCanvas);
}
}
}
MainWindow.xaml
<Window x:Class="_5_UI详解.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:_5_UI详解"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
运行: