說到布局(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》