浅谈 WPF布局
我们首先来了解一下图形化用户界面(Graphic User Interface)也就是我们常常听到的GUI。举个简单的例子,同样是数据,我们可以用控制台程序加格式控制符等输出,但是这些都不如GUI来的友好和方便。
WPF相对于其它只能使用编程语言进行UI设计,具有专门用于UI设计的XAML,并且能够确保界面布局能恰倒好处的适应不同的窗口尺寸。
我们来查看Window和Page的源码,发现Window的间接基类ContentControl和Page类都使用了一个object类型的Content属性。所以它只能包含一个元素,但是我们想放置多个元素怎么办呢?这个时候我们就需要使用布局容器。
为什么布局容器又可以添加多个元素呢?所有的WPF布局容器都派生自System.Windows.Controls.Panel这个抽象类。我们从类层次结构图中就不难发现它所包含的一系列布局容器。我们再来看看这个Panel类的源代码,就会发现该类有一个ContentProperty("Children")特性,所以我们会在该类中找到一个UIElementCollection类型(该类实现了IList接口)的Children属性。只要是继承自UIElement的类,都可以添加到布局容器中。
下面让我们来看看其中的一些布局容器以及与之相关联的控件属性。
StackPanel
它是最简单的布局容器,允许子元素在单行或者单列以堆栈的形式放置。
<StackPanel Orientation="Vertical" Background="LightCyan">
<Label Background="LemonChiffon">A Button Stack</Label>
<Button>Button A</Button>
<Button>Button B</Button>
<Button>Button C</Button>
</StackPanel>
我们运行会发现,StackPanel容器会充满整个窗口,因为它的HorizontalAlignment、VerticalAlignment属性值都是Stretch。
子元素是按照自上而下的方式排列的,因为我们设置了Orientation属性(默认值就是Vertical,所以这里我们可以不设置该属性);如果设置成Horizontal,就会从左到右排列。在默认情况下,每个子元素的高度都适合与它们自己内容的高度。如果是Horizontal,每个子元素的宽度都适合它们自己内容的长度。
我们拉伸运行的WPF程序,会发现StackPanel始终会充满整个窗口,子元素也会根据设置做相应的变化。
我们可以设置子元素的一些属性配合布局容器的属性,来决定布局。常见的属性有:HorizontalAlignment、VerticalAlignment、Margin、MinWidth、MinHeight、MaxWidth、MaxHeight、Height、Width。
<Window x:Class="WPFDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="200" Height="350"> <StackPanel Background="LightCyan">
<Label Background="LemonChiffon">A Button Stack</Label>
<Button HorizontalAlignment="Left">Button A</Button>
<Button HorizontalAlignment="Center">Button B</Button>
<Button HorizontalAlignment="Right">Button C</Button>
<Button Margin="5" Height="40" Width="100" HorizontalAlignment="Right">Button D</Button>
<Button MinWidth="320">Button E</Button>
</StackPanel> </Window>
运行这个程序,我们就会发现A、B、C三个Button分别位于水平方向上的不同位置;Button D距离四周的元素有5个单位的距离,并且指定了该按钮的高度和宽度;Button E指定了MinWidth,远大于Window的200,所以刚运行的时候左边被截断,需要我们通过拉伸才可完全看见。
Grid
顾名思义,Grid会以网格的形式对内容元素们进行布局。它具有如下的特点:
· 可以通过RowDefinitions和ColumnDefinitions属性,它们分别是RowDefinition和ColumnDefinition集合。定义任意多的行和列。
· 行的高度,列的宽度可以使用绝对数值(double数值加单位后缀px、in、cm、pt,不过在设置的时候最好不要加单位),比例值(double数值后加一个*号),自动值(字符串Auto)来灵活设置。
· 内部元素可以使用Grid的附加属性Grid.Row、Grid.Column、Grid.RowSpan、Grid.ColumnSpan设置自己所在的行、列、纵向跨几行、横向跨几列。
· 可以设置子元素的对齐方向。
<Grid VerticalAlignment="Top" HorizontalAlignment="Left" ShowGridLines="True" Width="250" Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
<RowDefinition Height="1.5*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions> <TextBlock FontSize="20" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="0">2013 Products Shipped</TextBlock>
<TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center">Quarter 1</TextBlock>
<TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center">Quarter 2</TextBlock>
<TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Center">Quarter 3</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center">50000</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="1" VerticalAlignment="Center">100000</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">150000</TextBlock>
<TextBlock FontSize="16" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="3">Total Units: 300000</TextBlock>
</Grid>
在这个示例中,我们还设置了ShowGridLines属性,它会生成虚线的边框。我们可以修改该边框,具体可以查看陈希章老师的这篇文章:为WPF和Silverlight的Grid添加边框。
我们还可以使用UseLayoutRounding属性来控制布局舍入。
我们还可以使用GridSplitter来拖动分割窗口。
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions> <Button>1</Button>
<Button Grid.Column="2">2</Button>
<Button Grid.Row="2">3</Button>
<Button Grid.Column="2" Grid.Row="2">4</Button> <GridSplitter Grid.Column="1" Grid.Row="0" Grid.RowSpan="3" Width="2" VerticalAlignment="Stretch" HorizontalAlignment="Center" ShowsPreview="True"></GridSplitter> </Grid>
这是一个左右拖动的分割窗口,所以我们把GridSplitter竖立放置铺满(VerticalAlignment="Stretch"),并跨行(Grid.RowSpan="3"),还要设置它的宽度Width(这样才可见);最后还要设置列的宽度为自动值Auto。我们还看到ShowsPreview属性为True,这个是当我们拖动分割条时,会有一个会射的阴影跟随鼠标运行,以显示预览。同理,我可以设置上下拖动的分割线,这里就不过多叙述了。
还有一个比较有意思的是SharedSizeGroup特性。
<Grid Margin="3">
<StackPanel>
<StackPanel Grid.IsSharedSizeScope="True">
<Grid Grid.Row="0" Margin="3" Background="LightYellow" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TextLabel"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions> <Label Margin="5">A very long bit of text</Label>
<Label Grid.Column="1" Margin="5">More text</Label>
<TextBox Grid.Column="2" Margin="5">A text box</TextBox>
</Grid>
<Label Grid.Row="1" >Some text in between the two grids...</Label>
<Grid Grid.Row="2" Margin="3" Background="LightYellow" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TextLabel"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions> <Label Margin="5">Short</Label>
<TextBox Grid.Column="1" Margin="5">A text box</TextBox>
</Grid>
</StackPanel>
</StackPanel>
</Grid>
我们可以设置需要共享尺寸的列ColumnDefinition或者行RowDefinition的SharedSizeGroup属性,把他们都设置成同一个值;然后再把Grid的IsSharedSizeScope附加属性设置到父容器上,并设置为True。(本例嵌套了2个StackPanel就是为了说明IsSharedSizeScope的设置方式,其实完全没有必要嵌套2个StackPanel,直接就可以设置在Grid上)
还有一个更简单的网格布局容器,UniformGrid,它可以直接设置Rows、Columns属性,设置行列数;它没有Rows、Columns这些附加属性,是按照子元素的添加的顺序由左到右,由上到下排列的。
Canvas
直译就是画布的意思。它通常用于一些设计基本不会再有改动的小型布局。
Canvas布局容器是最轻量级的布局容器,它没有包含负责的布局逻辑,以改变其子元素的首选尺寸。
我们可以设置Canvas.Left、Canvas.Top(或者Canvas.Right、Canvas.Buttom)附加属性来定位子元素的位置。
<Canvas>
<Button Canvas.Left="10" Canvas.Top="10">(10,10)</Button>
<Button Canvas.Left="120" Canvas.Top="30">(120,30)</Button>
<Button Canvas.Left="60" Canvas.Top="80" Width="50" Height="50" Canvas.ZIndex="1">(60,80)</Button>
<Button Canvas.Left="70" Canvas.Top="120" Width="100" Height="50">(70,120)</Button>
<Button Canvas.Left="80" Canvas.Top="150" Width="100" Height="50">(60,80)</Button>
</Canvas>
默认情况下,所有子元素的都具有相同的ZIndex属性值0;如果子元素的ZIndex值相同,就按照他们在Canvas中添加的先后顺序进行显示。所以上一个示例中,最后一个Button会显示在倒数第二个Button上面;第三个因为我们显示设置了ZIndex的值为1,大于默认值0,所以第三个在第四个上面。
这一节我们讲了3个非常具有代表性的布局容器,当然需要做好布局是一件非常困难的事情,需要考虑全面。所以还需要我们真正动手做的时候,不断的积累经验。这里只是一个简单的介绍布局容器。下一节,我们会来介绍一下WPF的控件。
浅谈 WPF布局的更多相关文章
- 浅谈WPF页间导航
浅谈WPF页间导航 使用导航的目的是从一个页面进入到另一个页面.无论是预先决定的线性顺序(向导)还是基于层次的用户驱动程序(大部分网站的形式),或者动态生成的路径,主要有3种方法实现:调用Naviga ...
- 浅谈WPF依赖项属性
浅谈WPF依赖项属性 0. 引言 依赖项属性虽然在使用上和CLR属性一样,但是它是WPF特有的,不同于CLR属性.只是封装为我们常用CLR的属性,在语法使用上和CLR属性一样.WPF中一些功能:动画, ...
- 浅谈 Qt 布局那些事
Qt 布局那些事是本文介绍的内容,直接进入主题.GridLayout是一个非常强大的布局管理器,它可以实现很多复杂的布局,名字中暗示它将所有控件放置在类似网格的布局中.^__^GridLayout有两 ...
- 浅谈WPF中对控件的位图特效(WPF Bitmap Effects)
原文:浅谈WPF中对控件的位图特效(WPF Bitmap Effects) -------------------------------------------------------------- ...
- 浅谈WPF本质中的数据和行为
WPF缩写为Windows Presentation Foundation的缩写,本文所要谈的就是WPF本质中的数据和行为,希望通过本文能对大家了解WPF本质有所帮助. 如果自己来做一个UI框架,我们 ...
- 浅谈 WPF控件
首先我们必须知道在WPF中,控件通常被描述为和用户交互的元素,也就是能够接收焦点并响应键盘.鼠标输入的元素.我们可以把控件想象成一个容器,容器里装的东西就是它的内容.控件的内容可以是数据,也可以是控件 ...
- 浅谈qt 布局器
在一个颜值当道的今天,无论买衣服,买车还是追星,颜值的高低已经变成了大家最看重的(不管男性女性都一样,千万别和我说你不是):而对于程序猿来说,开发一款软件,不再只注重逻辑和稳定性,美观和用户友好性也是 ...
- 浅谈CSS布局
在No.4中谈及了下盒子模型,引出布局模型 1.布局模型有三类: 1)流动模型 flow(默认) 2)浮动模型 float 3)层模型 layer 2.文档流 :指的是文本沿着从左到右的方向展开 ...
- 浅谈Android布局
在前面的博客中,小编介绍了Android的极光推送以及如何实现登录的一个小demo,对于xml布局页面,摆控件这块的内容,小编还不是很熟练,今天小编主要简单总结一下在Android中的布局,学习过An ...
随机推荐
- 【转】google谷歌百度收录网站的技巧方法,如何让百度收录?
下面由本人巴山给大家讲述一下搜索引擎收录网站的技巧虚拟主机 (1)在网站上线前,要有足够多的内容网站优化 确保网站在正式上线的时候,有100页以上的充实内容,而且这些内容尽可能的进行下编辑,优化,自己 ...
- oracle 常用技巧及脚本
[Q]怎么样查询特殊字符,如通配符%与_ [A]select * from table where name like 'A/_%' escape '/' [Q]如何插入单引号到数据库表中 [A]可以 ...
- 基于JQuery的渐隐渐现轮播
<div id="ads"> <div> <!--轮播图片--> <ul> <li><a href="# ...
- JavaScript作用域(链)学习笔记
作用域是javascript老生常谈的问题,在面试题中也经常出现.此文记录本人对js作用域的理解.从以下三个方面深入探讨js作用域和js作用域链. 1.什么是作用域? 2.什么是作用域链? 3.常见面 ...
- 【CSS3】---only-child选择器+only-of-type选择器
only-child选择器 “:only-child”选择器选择的是父元素中只有一个子元素,而且只有唯一的一个子元素.也就是说,匹配的元素的父元素中仅有一个子元素,而且是一个唯一的子元素. 示例演示 ...
- win8升级win10后的windows.old怎么删除
现在win10只是出了预览版本,还没有出正式版,但是相信一部分朋友都与小D一样,喜欢尝鲜,已上用上了win10了. 有些人是通过win8或是8.1直接安装升级上去的,这样操作是安装方便,但是系统会为了 ...
- public animal this[int index]|索引器的使用
学习如何使用索引器,索引器的使用是public 类型 this[int index]{get{};set{}} ,访问通过类的实例(对象)加[i], 例如animal[i],就像访问数组一样,其实就是 ...
- MVC 开启gzip压缩
using System.IO; using System.IO.Compression; using System.Web; using System.Web.Mvc; public class C ...
- UI3_UIbarButtonItem
// // AppDelegate.m // UI3_UIbarButtonItem // // Created by zhangxueming on 15/7/6. // Copyright (c) ...
- 9款经典华丽的CSS3分享按钮
如果你经常活跃在一些社交网站上,那么你肯定会看到过很多形式各异的分享按钮,目前由于HTML5和CSS3的普及,很多分享按钮也都应用了CSS3样式,甚至会有很多带有动画的CSS3分享按钮.本文就向大家介 ...