本主題描述 Windows Presentation Foundation (WPF) 布局系統。瞭解在構造外觀醒目、效能優良的使用者介面時如何以及何時進行布局計算是非常重要的。
布局系統 術語“布局”描述測量和排列 Panel 元素的 Children 集合的成員、然後在螢幕上繪製它們的過程。這是一個計算密集型過程,即 Children 集合越大,執行的計算次數就越多。根據擁有該集合的 Panel 元素所定義的布局行為,還可能會增加複雜性。如果不需要較為複雜的 Panel(如 Grid),則可以使用構造相對簡單的布局(如 Canvas),這種布局可產生更佳的效能。
每當子 UIElement 改變其位置時,布局系統就可能觸發一個新的處理過程。因此,瞭解哪些事件會調用布局系統就很重要,因為不必要的調用可能導致應用程式效能變差。
簡單地說,布局是一個遞迴系統,實現在螢幕上對元素進行大小調整、定位和繪製。布局系統為 Children 集合的每個成員完成兩個處理過程:測量處理過程和排列處理過程。每個子 Panel 均提供自己的 MeasureOverride 和 ArrangeOverride 方法,以實現自己特定的布局行為。不論何時調用布局系統,都會發生以下系列事件。
子 UIElement 通過首先測量它的核心屬性來開始版面配置階段。
計算在 FrameworkElement 上定義的大小調整屬性,例如 Width、Height 和 Margin。
應用 Panel 特定邏輯,例如 Dock 方向或堆棧 Orientation。
測量所有子級後排列內容。
Children 集合繪製到螢幕。
如果其他 Children 添加到集合、應用 LayoutTransform 或調用 UpdateLayout 方法,會再次調用此過程。
下面的小節將更詳盡地定義此過程及其調用方式。
元素邊界框 在 Windows Presentation Foundation (WPF) 中構思應用程式布局時,瞭解環繞所有元素的邊界框非常重要。這有助於您理解布局系統的行為。布局系統使用的每個 FrameworkElement 可以被視為是嵌入到布局分區中的矩形。LayoutInformation 類會公開,可以返回元素布局分配的幾何邊界或槽。矩形的大小是由系統通過計算可用螢幕空間、任意約束的大小、布局特定屬性(如邊距和填充)及父 Panel 元素的個別行為來確定的。通過處理此資料,系統將能夠計算給定的 Panel 的所有子級的位置。牢記在父元素上定義的哪些大小調整特性(如 Border)會影響其子級,這非常重要。
例如,請考慮下面的簡單布局方案。
可以使用以下可擴充應用程式標記語言 (XAML) 來實現此布局。
此單獨的 TextBlock 元素是在 Grid 內承載的,而文本僅填充在其所在列的左上方,為 TextBlock 分配的空間實際更大。可以使用 GetLayoutSlot 方法檢索任意 FrameworkElement 的邊界框。使用此方法,TextBlock 元素的邊界框是疊加的,這可能是因為 TextBlock 是在 Grid(它是允許共用布局座標的 Panel 元素)內承載的。
現在很明顯該元素由白線環繞,分配給 TextBlock 元素的分區實際遠遠大於其填充的空間。由於還有其他元素添加到 Grid,此分配可能會收縮或擴充,這取決於所添加元素的類型和大小。
將會使用 GetLayoutSlot 方法(它是一項用於顯示元素邊界框的有用技術)返回 TextBlock 的布局槽並將其轉換成 Path。
測量和排列子控制項 當呈現 Window 對象的內容時,會自動調用布局系統。為了顯示內容,視窗的 Content 必須定義根 Panel(用於定義架構,Children 是按架構在螢幕上組織的)。
布局的第一個處理過程是測量處理過程,將在此對 Children 集合的每個成員進行計算。此過程將以調用 Measure 方法開始。此方法將在父 Panel 元素的實現中調用,無需為要出現的布局顯式調用該方法。
首先,將計算 UIElement 的本機大小屬性,如 Clip 和 Visibility。這將產生一個名為 constraintSize 的傳遞給 MeasureCore 的值。
其次,會處理在 FrameworkElement 上定義的架構屬性,這將影響 constraintSize 的值。這些屬性旨在描述基礎 UIElement 的大小調整特性,例如其 Height、Width、Margin 和 Style。上述每個屬性均可能改變顯示元素所必需的空間。然後,將用 constraintSize 作為一個參數調用 MeasureOverride。
說明: 在 Height、Width、ActualHeight 和 ActualWidth 的屬性之間存在著差異。例如,ActualHeight 屬性是基於其他高度輸入和布局系統的計算值。該值是由布局系統本身基於實際呈現處理過程設定的,因此可能稍微小於屬性(例如作為輸入更改基礎的 Height)的設定值。
由於 ActualHeight 是一個計算值,所以您應該知道,作為布局系統多個操作的結果,該值可能有多次或不斷增加的報告的更改。布局系統可能正在計運算元元素所需的測量空間、父元素的約束等。
測量處理過程的最終目標是讓子級確定其 DesiredSize,這是在 MeasureCore 調用期間發生的。該值由 Measure 儲存,以便在內容排列過程期間使用。
此排列過程將以調用 Arrange 方法開始。在排列處理過程期間,父 Panel 元素產生一個代表子級邊界的矩形。該值會傳遞給 ArrangeCore 方法以便進行處理。
ArrangeCore 方法計運算元級的 DesiredSize,計算可能影響該元素呈現大小的任何其他邊距,並產生 arrangeSize(作為參數傳遞給 Panel 的 ArrangeOverride)。ArrangeOverride 產生子級的 finalSize,最後,ArrangeCore 方法執行位移屬性(例如邊距和對齊)的最終計算,並將子級放在其布局槽內。子級無需(且通常不會)填充整個分配空間。然後,控制項返回到父 Panel,至此版面配置階段完成。
面板元素和自訂布局行為 Windows Presentation Foundation (WPF) 包括 Panel 元素的派生套件,可以實現許多複雜的布局。常見方案(如堆棧元素)可以使用 StackPanel 元素方便地實現,而較為複雜和自由流動的布局可以使用 Canvas 來實現。
下表概括了可用的布局元素。
面板名稱 說明
Canvas
定義一個地區,在此地區內,您可以使用相對於 Canvas 地區的座標顯式定位子項目。
DockPanel
定義一個地區,在此地區中,您可以使子項目互相水平或垂直排列。
Grid
定義由行和列組成的靈活網格地區。
StackPanel
將子項目排列成一行(可沿水平或垂直方向)。
VirtualizingPanel 為“虛擬化”其子資料集合的 Panel 元素提供一個架構。這是一個抽象類別。
WrapPanel
從左至右按順序位置定位子項目,在包含框的邊緣處將內容斷開至下一行。後續排序按照從上至下或從右至左的順序進行,具體取決於 Orientation 屬性的值。 對於其所需應用程式布局不可能使用任意預定義的 Panel 元素來實現的方案,您可以通過從 Panel 繼承、並重寫 MeasureOverride 和 ArrangeOverride 方法來實現自訂布局行為。
布局效能注意事項 布局是一個遞迴過程。Children 集合中的每個子項目會在每次調用系統期間得到處理。因此,應避免在不必要時觸發系統。以下提示有助於實現更高的效能。
其值可能導致布局系統被初始化的相關性屬性會標記為公用標誌。AffectsMeasure 和 AffectsArrange 提供有關哪個屬性值更改會強制執行布局系統的遞迴更新的有用提示。通常,任何可能影響元素邊界框大小的屬性應將 AffectsMeasure 標誌設定為 true。
LayoutTransform 可能是影響使用者介面 (UI) 內容的非常有用的方式。不過,如果轉換的效果無需對其他元素的位置施加影響,則最好改為使用 RenderTransform,因為 RenderTransform 不會調用布局系統。LayoutTransform 會應用其轉換,並強制對帳戶執行遞迴布局更新,以擷取受影響元素的新位置。
避免不必要地調用 UpdateLayout。此方法強制遞迴布局更新,但常常卻是不必要的。除非您確認需要進行完整更新,否則請依賴布局系統來為您調用此方法。
當處理大型 Children 集合時,請考慮使用 VirtualizingStackPanel 而非常規 StackPanel。通過“虛擬化”子項目,VirtualizingStackPanel 僅在記憶體中保留當前位於父 ViewPort 內的對象。因此,在大多數情況下效能會得到極大改進。
摘自:http://developer.51cto.com/art/200808/86734.htm