说到布局(Layout),我想大家都不会陌生,不管是做Web开发,还是移动应用,还是桌面软件,只要是涉及到UI展现的,都需要做界面布局。WPF布局系统比Winform时候的布局要先进了很多,基于流式布局,越来越像Web开发模式。
本篇将从如下5个方面来讨论WPF布局系统:
1、元素边界框。
2、面板
3、测量和排列
4、Layout性能关注
5、布局舍入
一、元素边界框(Element Bounding Boxes)
如下图,你可以把WPF的界面想象成一个停车场,停车场里的车就是界面上的元素,车必须停在事先画好的方框里面。这个方框在WPF布局里就是元素边界框。与停车场不同的是,WPF布局里面这个方框的尺寸和位置排列是计算出来的。如果现实中有这样的智能停车场也不错哦~~我们可以通过WPF提供的类System.Windows.Controls.Primitives.LayoutInformation的方法获取Layout信息。
二、面板Panel
Panel就是一个容器,里面可以放置UI元素。Panel中也可以嵌套Panel。Panel要负责计算器子元素的尺寸,位置,和维度。WPF框架提供了如下图一些Panel,我们工作中主要是使用它们,不过如果需要,我们也可以开发自己的个性化的Panel,只要继承自Panel并重写MeasureOverride 和 ArrangeOverride方法。例子:http://go.microsoft.com/fwlink/?LinkID=159982
本表来自微软网站http://msdn.microsoft.com/en-us/library/ms754152.aspx
Element Name |
UI Panel? |
Description |
---|---|---|
Yes |
Defines an area within which you can explicitly position child elements by coordinates relative to the Canvas area. |
|
Yes |
Defines an area within which you can arrange child elements either horizontally or vertically, relative to each other. |
|
Yes |
Defines a flexible grid area consisting of columns and rows. Child elements of a Grid can be positioned precisely using the Margin property. |
|
Yes |
Arranges child elements into a single line that can be oriented horizontally or vertically. |
|
No |
Handles the layout of tab buttons in a TabControl. |
|
No |
Arranges content within a ToolBar control. |
|
No |
UniformGrid is used to arrange children in a grid with all equal cell sizes. |
|
No |
Provides a base class for panels that can "virtualize" their children collection. |
|
Yes |
Arranges and virtualizes content on a single line oriented horizontally or vertically. |
|
Yes |
WrapPanel positions child elements in sequential position from left to right, breaking content to the next line at the edge of the containing box. Subsequent ordering happens sequentially from top to bottom or right to left, depending on the value of the Orientation property. |
但是,如下面也有一些空间不是派生自Panel,也可以作为容器来使用。
InkCanvas
GroupBox
Viewbox
Expander
Popup
三、测量(Measure)和排列(arrange)
我们已经知道,WPF界面上的每个元素的边界框尺寸和排列是WPF自动计算出来的。那么这个智能布局的过程是怎么样呢?两个步骤:measure and arrange. Layout系统要为每个Panel中的每个子元素进行这两个步骤的处理。由于Panel是可以嵌套的,可以推断这是个递归的处理过程。Layout处理的过程如下图所示:
我们在学习WPF框架的时候已经知道,所有UI元素的根元素是UIElement类型,UIElement中定义了一些基本的关于UI显示的属性(如clip和Visibility)。在UIElement.Measure(Size availableSize)方法执行阶段,就是要对这些基本属性做评估,得到合适的Size。同样,FrameworkElement.MeasureCore(Size availableSize)方法评估在FrameworkElement中定义且有可能影响UI布局的属性,得出更合适的Size。这个Size将被传递给FrameworkElement.MeasureOverride(Size availableSize),WPF提供的Panel类型(如Grid)中就会重写该方法来处理,处理完后将得到一个系统期望的Size(可称之为DesiredSize),Layout系统将按照这个Size来显示该Element。到此测量(Measure)阶段结束。当Size确定以后,把Size包装为Rect实例,传递给UIElement.Arrange(Rect finalRect),开始进行排列(arrange)处理,根据Size参数,Arrange方法将为元素创建边界框(就是第一节说的那个元素边界框),边框信息将会打包到Rect实例传递给FrameworkElement.ArrangeCore(Rect finalRect),ArrangeCore将继续评估DesiredSize,将会计算边界留白(Margin,Pading..)等信息,得到arrangeSize,并传递FrameworkElement.ArrangeOverride(Size finalSize),这个方法又是可重写的,WPF提供的Panel类型(如Grid)中就会重写该方法来处理,最终得到finalSize。得到finalSize后,ArrangeOverride执行完毕,控制权回到ArrangeCore方法,ArrangeCore把该Element放到它的边界框中。到此,该Element的Layout处理完成。
四、Layout性能问题
在做项目的时候,我们总想尽可能提高软件的性能。开发WPF软件,Layout只是个小部分,但是性能问题还是要注意。
1、由于界面上的每一个UI元素都会进行Layout处理(measure and arrange),那么UI元素越多,处理的次数就越多,性能就会下降。因此,我们要尽可能用最少的UI元素来实现界面。
2、由于在Layout处理过程中,将会评估Element的会影响UI布局的属性(如,width,height,margin等),这些属性值改变的时候将会激发layout处理过程。因此,我们应该尽可能减少改变这些属性值。
五、布局舍入(Layout Rounding)
当UseLayoutRounding=true的时候才会做layout舍入处理。这个处理就是为了使界面适应不同的分辨率。什么Dpi计算等等处理,开发时不用关心了。。如果不需要舍入,就不要设为True,以免影响性能。
本文主要参考自:http://msdn.microsoft.com/en-us/library/ms745058.aspx《深入浅出WPF》和《Pro WPF in c# 2010》