重要的應用程式介面
版面配置是定義用戶介面視覺結構的過程。 在 XAML 中描述版面配置的主要機制是透過面板,這些是可讓您放置及排列其中 UI 元素的容器物件。 配置可以是 XAML 應用程式的昂貴部分,無論是 CPU 使用量還是記憶體額外負荷。 以下是一些您可以採取來改善 XAML 應用程式的版面配置效能的簡單步驟。
簡化版面結構
配置效能的最大提升來自於簡化UI元素樹狀結構的階層式結構。 面板存在於可視化樹狀結構中,但它們是結構元素,而不是 像素產生 元素,例如 Button 或 Rectangle。 藉由減少非像素產生元素的數目來簡化樹狀結構,通常會大幅提升效能。
許多用戶介面都是透過巢狀面板來實作,這會導致面板和元素形成深層且複雜的樹狀結構。 巢狀面板很方便,但在許多情況下,可以使用更複雜的單一面板來達成相同的UI。 使用單一面板可提供更佳的效能。
減少版面配置結構的時機
以簡單的方式減少版面配置結構,例如,從最上層頁面減少一個巢狀面板,沒有明顯的效果。
最大的效能提升來自於減少 UI 中重複的配置結構,例如 ListView 或 GridView。 這些 ItemsControl 元素會使用 DataTemplate,其會定義多次具現化的 UI 元素子樹。 在應用程式中重複多次相同的子樹時,該子樹效能的任何改善都會對應用程式的整體效能產生乘法影響。
範例
請考慮下列 UI。
這些範例示範 3 種實作相同 UI 的方式。 每個實作選擇都會在畫面上產生幾乎完全相同的圖元,但在實作詳細數據中會有很大的差異。
選項 1:巢狀 StackPanel 元素
雖然這是最簡單的模型,但它會使用5個面板元素,並產生顯著的額外負荷。
<StackPanel>
<TextBlock Text="Options:" />
<StackPanel Orientation="Horizontal">
<CheckBox Content="Power User" />
<CheckBox Content="Admin" Margin="20,0,0,0" />
</StackPanel>
<TextBlock Text="Basic information:" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:" Width="75" />
<TextBox Width="200" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Email:" Width="75" />
<TextBox Width="200" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Password:" Width="75" />
<TextBox Width="200" />
</StackPanel>
<Button Content="Save" />
</StackPanel>
選項 2:單一 方格
Grid 會新增一些複雜度,但只使用單一面板元件。
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="Options:" Grid.ColumnSpan="2" />
<CheckBox Content="Power User" Grid.Row="1" Grid.ColumnSpan="2" />
<CheckBox Content="Admin" Margin="150,0,0,0" Grid.Row="1" Grid.ColumnSpan="2" />
<TextBlock Text="Basic information:" Grid.Row="2" Grid.ColumnSpan="2" />
<TextBlock Text="Name:" Width="75" Grid.Row="3" />
<TextBox Width="200" Grid.Row="3" Grid.Column="1" />
<TextBlock Text="Email:" Width="75" Grid.Row="4" />
<TextBox Width="200" Grid.Row="4" Grid.Column="1" />
<TextBlock Text="Password:" Width="75" Grid.Row="5" />
<TextBox Width="200" Grid.Row="5" Grid.Column="1" />
<Button Content="Save" Grid.Row="6" />
</Grid>
選項 3:單一 RelativePanel:
這個單一面板也比使用巢狀面板複雜一點,但可能比 Grid 更容易瞭解和維護。
<RelativePanel>
<TextBlock Text="Options:" x:Name="Options" />
<CheckBox Content="Power User" x:Name="PowerUser" RelativePanel.Below="Options" />
<CheckBox Content="Admin" Margin="20,0,0,0"
RelativePanel.RightOf="PowerUser" RelativePanel.Below="Options" />
<TextBlock Text="Basic information:" x:Name="BasicInformation"
RelativePanel.Below="PowerUser" />
<TextBlock Text="Name:" RelativePanel.AlignVerticalCenterWith="NameBox" />
<TextBox Width="200" Margin="75,0,0,0" x:Name="NameBox"
RelativePanel.Below="BasicInformation" />
<TextBlock Text="Email:" RelativePanel.AlignVerticalCenterWith="EmailBox" />
<TextBox Width="200" Margin="75,0,0,0" x:Name="EmailBox"
RelativePanel.Below="NameBox" />
<TextBlock Text="Password:" RelativePanel.AlignVerticalCenterWith="PasswordBox" />
<TextBox Width="200" Margin="75,0,0,0" x:Name="PasswordBox"
RelativePanel.Below="EmailBox" />
<Button Content="Save" RelativePanel.Below="PasswordBox" />
</RelativePanel>
如這些範例所示,有許多方式可以達到相同的UI。 應該仔細考慮所有的取捨,包括效能、可讀性和可維護性。
使用單個儲存格網格來處理重疊的使用者介面
常見的使用者介面需求是讓元素互相重疊的版面配置。 一般而言,會使用填充、邊距、對齊和轉換來以這種方式放置元素。 XAML 方格 控件已優化,可改善重疊元素的版面配置效能。
重要 要查看改進,請使用單個儲存格 方格。 請勿定義 RowDefinitions 或 ColumnDefinitions。
範例
<Grid>
<Ellipse Fill="Red" Width="200" Height="200" />
<TextBlock Text="Test"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
<Grid Width="200" BorderBrush="Black" BorderThickness="1">
<TextBlock Text="Test1" HorizontalAlignment="Left" />
<TextBlock Text="Test2" HorizontalAlignment="Right" />
</Grid>
使用面板的內建框線屬性
Grid、 StackPanel、 RelativePanel 和 ContentPresenter 控件具有內建框線屬性,可讓您在周圍繪製框線,而不需要將額外的 Border 元素新增至 XAML。 支援內建框線的新屬性包括: BorderBrush、 BorderThickness、 CornerRadius 和 Padding。 每一個都是 DependencyProperty,因此您可以將它們與系結和動畫搭配使用。 其設計目的是要完整取代個別的 Border 元素。
如果您的 UI 在這些面板周圍有 Border 元素,請改用內建框線,以在應用程式的版面配置結構中省去額外的元素。 如先前所述,這可能會大幅節省成本,特別是在重複UI的情況下。
範例
<RelativePanel BorderBrush="Red" BorderThickness="2" CornerRadius="10" Padding="12">
<TextBox x:Name="textBox1" RelativePanel.AlignLeftWithPanel="True"/>
<Button Content="Submit" RelativePanel.Below="textBox1"/>
</RelativePanel>
使用 SizeChanged 事件來回應佈局變更
FrameworkElement 類別會公開兩個類似的事件來回應版面配置變更:LayoutUpdated 和 SizeChanged。 當元素在佈局過程中調整大小時,您可能會使用其中一個事件來獲取通知。 這兩個事件的語意不同,而在選擇這兩個事件時需要考慮重要的效能問題。
為了達到良好的效能,SizeChanged 幾乎總是正確的選擇。 SizeChanged 具有直覺式語意。 當 FrameworkElement 的大小已更新時,會在版面配置期間引發。
LayoutUpdated 也會在版面配置時引發,但它具有全域語意,每當更新任何元素時,就會在每個元素上引發。 通常只會在事件處理程式中執行本機處理,在此情況下,程式代碼的執行頻率會比需要更多。 只有當您需要知道元素重新置放而不變更大小時,才使用 LayoutUpdated,這種情況並不常見。
在面板之間選擇
在個別面板之間選擇時,效能通常不是考慮事項。 選擇通常是藉由考慮哪一個面板提供最接近您所實作UI的配置行為所做出。 例如,如果您在 Grid、StackPanel 以及 RelativePanel之間選擇,您應該選擇與您實作心理模型最接近的面板。
每個 XAML 面板都會針對良好的效能進行優化,而且所有面板都為類似的 UI 提供類似的效能。