版面配置

本主題描述 Windows Presentation Foundation (WPF) 版面配置系統。 瞭解配置計算的發生方式和時機,對於在 WPF 中建立使用者介面至關重要。

本主題包含下列幾節:

項目週框方塊

考慮 WPF 中的版面配置時,請務必瞭解圍繞所有元素的周框方塊。 配置系統所取用的每個 FrameworkElement 都可以視為配置中位置的矩形。 類別 LayoutInformation 會傳回元素配置或位置的界限。 矩形的大小取決於計算可用的螢幕空間、任何條件約束的大小、版面配置特定屬性(例如邊界和邊框間距),以及父 Panel 元素的個別行為。 處理此資料時,配置系統能夠計算特定 Panel 的所有子系位置。 請務必記住,在父元素上定義的調整大小特性,例如 Border ,會影響其子系。

下圖顯示簡單的版面配置。

Screenshot that shows a typical grid, no bounding box superimposed.

您可以使用下列 XAML 來達成此配置。

<Grid Name="myGrid" Background="LightSteelBlue" Height="150">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="250"/>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
    <RowDefinition />
  </Grid.RowDefinitions>
  <TextBlock Name="txt1" Margin="5" FontSize="16" FontFamily="Verdana" Grid.Column="0" Grid.Row="0">Hello World!</TextBlock>
  <Button Click="getLayoutSlot1" Width="125" Height="25" Grid.Column="0" Grid.Row="1">Show Bounding Box</Button>
  <TextBlock Name="txt2" Grid.Column="1" Grid.Row="2"/>
</Grid>

TextBlockGrid 專案裝載于 內。 雖然文字只會填滿第一個資料行的左上角,但 配置的空間 TextBlock 實際上要大得多。 您可以使用 方法擷取 GetLayoutSlot 任何 FrameworkElement 的周框方塊。 下圖顯示 專案的 TextBlock 周框方塊。

Screenshot that shows that the TextBlock bounding box is now visible.

如黃色矩形所示,元素的配置空間 TextBlock 實際上會比它顯示大得多。 當其他元素新增至 Grid 時,此配置可能會壓縮或展開,視新增的專案類型和大小而定。

的配置位置 TextBlock 會使用 GetLayoutSlot 方法轉譯成 Path 。 這種方式可用於顯示項目的週框方塊。

private void getLayoutSlot1(object sender, System.Windows.RoutedEventArgs e)
{
    RectangleGeometry myRectangleGeometry = new RectangleGeometry();
    myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1);
    Path myPath = new Path();
    myPath.Data = myRectangleGeometry;
    myPath.Stroke = Brushes.LightGoldenrodYellow;
    myPath.StrokeThickness = 5;
    Grid.SetColumn(myPath, 0);
    Grid.SetRow(myPath, 0);
    myGrid.Children.Add(myPath);
    txt2.Text = "LayoutSlot is equal to " + LayoutInformation.GetLayoutSlot(txt1).ToString();
}
Private Sub getLayoutSlot1(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim myRectangleGeometry As New RectangleGeometry
    myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1)
    Dim myPath As New Path
    myPath.Data = myRectangleGeometry
    myPath.Stroke = Brushes.LightGoldenrodYellow
    myPath.StrokeThickness = 5
    Grid.SetColumn(myPath, 0)
    Grid.SetRow(myPath, 0)
    myGrid.Children.Add(myPath)
    txt2.Text = "LayoutSlot is equal to " + LayoutInformation.GetLayoutSlot(txt1).ToString()
End Sub

配置系統

簡單來說,版面配置是可調整項目大小、定位項目並在螢幕上繪製項目的遞迴系統。 更具體來說,版面配置描述測量和排列專案 Children 集合成員 Panel 的程式。 版面配置是需要大量處理的程序。 集合愈大 Children ,必須進行的計算數目愈大。 您也可以根據擁有集合的 元素所 Panel 定義的版面配置行為來引進複雜度。 相對簡單 Panel ,例如 Canvas ,的效能可能會明顯優於更複雜的 Panel ,例如 Grid

每次子系 UIElement 變更其位置時,它都有可能觸發配置系統的新傳遞。 因此,請務必了解可叫用配置系統的事件,因為不必要的叫用可能會導致不良的應用程式效能。 下列描述在叫用配置系統時所發生的程序。

  1. 子系 UIElement 會先測量其核心屬性,以開始配置程式。

  2. 評估上 FrameworkElement 定義的調整大小屬性,例如 WidthHeightMargin

  3. Panel套用特定邏輯,例如 Dock 方向或堆疊 Orientation

  4. 測量所有子系之後,會排列內容。

  5. 集合 Children 會在畫面上繪製。

  6. 如果將其他 Children 新增至集合、 LayoutTransform 套用 ,或 UpdateLayout 呼叫 方法,則會再次叫用進程。

下列各節會詳述定義此程序和其叫用方式。

測量和排列子系

配置系統會針對集合的每個 Children 成員、量值階段和排列階段完成兩次傳遞。 每個子系 Panel 都會提供自己的 MeasureOverrideArrangeOverride 方法,以達到自己的特定版面配置行為。

在量值階段期間,會評估集合的每個 Children 成員。 此程式會從呼叫 Measure 方法開始。 這個方法會在父 Panel 元素的實作內呼叫,而且不需要明確呼叫配置即可發生。

首先,會評估 的 UIElement 原生大小屬性,例如 ClipVisibility 。 這會產生名為 constraintSize 的值,這個值會傳遞至 MeasureCore

其次,在 上 FrameworkElement 定義的架構屬性會進行處理,這會影響 的值 constraintSize 。 這些屬性通常會描述基礎 UIElement 的大小特性,例如其 HeightWidthMarginStyle 。 所有這些屬性都可以變更顯示項目所需的空間。 MeasureOverride 接著會以 constraintSize 做為參數呼叫 。

注意

和 和 WidthActualHeightActualWidth 的屬性 Height 之間有差異。 例如, ActualHeight 屬性是以其他高度輸入和版面配置系統為基礎的計算值。 此值是由版面配置系統本身根據實際的轉譯階段所設定,因此可能會稍微落後于屬性的設定值,例如 Height ,這是輸入變更的基礎。

因為 ActualHeight 是計算值,所以您應該注意,由於配置系統的各種作業,可能會有多個或累加的回報變更。 配置系統可能會計算子項目所需的測量空間、父項目的條件約束,依此類推。

量值階段的最終目標是讓子系判斷其 DesiredSize ,這會在呼叫期間 MeasureCore 發生。 值 DesiredSize 會儲存在 Measure 內容排列階段期間使用。

排列傳遞的開頭是呼叫 Arrange 方法。 在排列階段期間,父 Panel 元素會產生代表子系界限的矩形。 這個值會傳遞至 ArrangeCore 方法進行處理。

方法 ArrangeCoreDesiredSize 評估子系的 ,並評估可能會影響專案轉譯大小的任何其他邊界。 ArrangeCore 會產生 arrangeSize ,其會傳遞至 ArrangeOverride 的 方法 Panel 做為參數。 ArrangeOverride 會產生 finalSize 子系的 。 最後, ArrangeCore 方法會執行位移屬性的最終評估,例如邊界和對齊方式,並將子系放在其版面配置位置內。 子系不需要 (通常也不會) 填入整個已配置的空間。 控制項接著會傳回父 Panel 代,且版面配置程式已完成。

面板項目和自訂版面配置行為

WPF 包含衍生自 Panel 的專案群組。 這些專案 Panel 可啟用許多複雜的版面配置。 例如,您可以使用 元素輕鬆達成 StackPanel 堆疊元素,而使用 Canvas 可以更複雜且自由流動的配置。

下表摘要說明可用的版面配置 Panel 元素。

面板名稱 描述
Canvas 定義區域,您可以透過相對於 Canvas 區域的座標明確定位子專案。
DockPanel 定義一個區域,可供您在其中以子元素彼此間相對的水平或垂直方式排列子元素。
Grid 定義彈性的格線區域,由欄與列組成。
StackPanel 將子元素排成單一行,以水平或垂直方式排列。
VirtualizingPanel 提供虛擬化其子資料收集之專案的架構 Panel 。 這是 abstract 類別。
WrapPanel 將子項目置放於由左至右的連續位置,其中會在包含方塊的邊緣將內容換至下一行。 後續順序會根據 屬性的值 Orientation ,從上到下或由右至左順序順序。

對於使用任何預先定義 Panel 元素而不需要配置的應用程式,可以藉由繼承 Panel 和覆 MeasureOverride 寫 和 ArrangeOverride 方法來達成自訂配置行為。

版面配置效能考量

版面配置是遞迴程序。 集合中的每個 Children 子專案會在配置系統的每個叫用期間進行處理。 因此,不需要時,應該避免觸發配置系統。 下列考量可協助您達到更佳的效能。

  • 請注意哪些屬性值變更將會由配置系統強制遞迴更新。

    使用公用旗標,可標記其值可以初始化配置系統的相依性屬性。 AffectsMeasure 並提供 AffectsArrange 實用線索,說明版面配置系統會強制遞迴更新屬性值變更。 一般而言,任何會影響專案周框方塊大小的屬性都應該將 AffectsMeasure 旗標設定為 true。 如需詳細資訊,請參閱相依性屬性概觀

  • 可能的話,請使用 RenderTransform 而非 LayoutTransform

    LayoutTransform對於影響使用者介面 (UI) 內容來說,可能是一種非常有用的方法。 不過,如果轉換的效果不需要影響其他元素的位置,最好改用 ,因為 RenderTransform 不會叫用 RenderTransform 配置系統。 LayoutTransform 套用其轉換,並強制遞迴版面配置更新以考慮受影響專案的新位置。

  • 避免對 UpdateLayout 進行不必要的呼叫。

    方法 UpdateLayout 會強制遞迴版面配置更新,而且通常不需要。 除非您確定需要完整更新,否則請依賴配置系統來呼叫此方法。

  • 使用大型 Children 集合時,請考慮使用 VirtualizingStackPanel 而非一般 StackPanel

    藉由虛擬化子集合, VirtualizingStackPanel 唯一會將目前在父系 ViewPort 內的物件保留在記憶體中。 因此,在大部分情況下,都可以大幅改善效能。

子像素轉譯和版面配置進位

WPF 圖形系統使用與裝置無關的單位來啟用解析度和裝置獨立性。 每個裝置獨立圖元都會使用每英吋 (DPI) 設定的系統點自動縮放。 這會為 WPF 應用程式提供適用于不同 DPI 設定的適當縮放比例,並讓應用程式自動感知 DPI。

不過,由於消除鋸齒,此 DPI 獨立可能會建立不規則的邊緣轉譯。 如果邊緣位置落在裝置像素中間,而不是裝置像素之間,則這些成品一般會看起來模糊或具有半透明邊緣。 配置系統提供一種方式,利用版面配置來進行這項的調整。 版面配置進位是配置系統會在版面配置階段期間將任何非整數像素值四捨五入。

預設會停用版面配置進位。 若要啟用版面配置四捨五入,請將 UseLayoutRounding 任何 FrameworkElement 上的 屬性設定為 true 。 因為這是相依性屬性,所以值將會傳播到視覺樹狀結構中的所有子系。 若要啟用整個 UI 的配置四捨五入,請將 設定 UseLayoutRoundingtrue 為根容器上的 。 如需範例,請參閱 UseLayoutRounding

後續步驟

了解如何測量和排列項目是了解版面配置的第一個步驟。 如需可用 Panel 專案的詳細資訊,請參閱 面板概觀 。 若要進一步了解會影響版面配置的各種定位屬性,請參閱對齊、邊界和填補概觀。 當您準備好將其全部放在輕量型應用程式中時,請參閱 逐步解說:我的第一個 WPF 桌面應用程式

另請參閱