Optimalkan tata letak XAML Anda

API penting

Tata letak adalah proses menentukan struktur visual untuk UI Anda. Mekanisme utama untuk menjelaskan tata letak di XAML adalah melalui panel, yang merupakan objek kontainer yang memungkinkan Anda memposisikan dan mengatur elemen UI di dalamnya. Tata letak dapat menjadi bagian mahal dari aplikasi XAML—baik dalam penggunaan CPU maupun overhead memori. Berikut adalah beberapa langkah sederhana yang dapat Anda ambil untuk meningkatkan performa tata letak aplikasi XAML Anda.

Mengurangi struktur tata letak

Perolehan terbesar dalam performa tata letak berasal dari menyederhanakan struktur hierarkis pohon elemen UI. Panel ada di pohon visual, tetapi merupakan elemen struktural, bukan elemen produksi piksel seperti Tombol atau Persegi Panjang. Menyederhanakan pohon dengan mengurangi jumlah elemen yang tidak menghasilkan piksel biasanya memberikan peningkatan performa yang signifikan.

Banyak UI diimplementasikan oleh panel bersarang yang menghasilkan pohon panel dan elemen yang dalam dan kompleks. Lebih mudah untuk menumpuk panel, tetapi dalam banyak kasus UI yang sama dapat dicapai dengan panel tunggal yang lebih kompleks. Menggunakan satu panel memberikan performa yang lebih baik.

Kapan harus mengurangi struktur tata letak

Mengurangi struktur tata letak dengan cara yang sepele—misalnya, mengurangi satu panel berlapis dari halaman tingkat atas Anda—tidak memiliki efek yang nyata.

Perolehan performa terbesar berasal dari mengurangi struktur tata letak yang diulang di UI, seperti dalam ListView atau GridView. Elemen ItemsControl ini menggunakan DataTemplate, yang mendefinisikan subtree elemen UI yang dibuat berkali-kali. Ketika subtree yang sama sedang diduplikasi berkali-kali di aplikasi Anda, peningkatan performa subtree tersebut memiliki efek multiplikatif pada performa keseluruhan aplikasi Anda.

Contoh

Pertimbangkan UI berikut.

Form layout example

Contoh-contoh ini menunjukkan 3 cara untuk menerapkan UI yang sama. Setiap pilihan implementasi menghasilkan piksel yang hampir identik di layar, tetapi secara substansial berbeda dalam detail implementasi.

Opsi1: Elemen StackPanel Berlapis

Meskipun ini adalah model yang paling sederhana, model ini menggunakan 5 elemen panel dan menghasilkan overhead yang signifikan.

  <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>

Opsi 2: Satu Kisi

Grid menambahkan beberapa kompleksitas, tetapi hanya menggunakan satu elemen panel.

<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>

Opsi 3: RelativePanel tunggal:

Panel tunggal ini juga sedikit lebih kompleks daripada menggunakan panel berlapis, tetapi mungkin lebih mudah dipahami dan dirawat daripada 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>

Seperti yang ditunjukkan oleh contoh-contoh ini, ada banyak cara untuk mencapai UI yang sama. Anda harus memilih dengan hati-hati mempertimbangkan semua tradeoff, termasuk performa, keterbacaan, dan keberlanjutan.

Menggunakan kisi sel tunggal untuk antarmuka pengguna yang tumpang tindih

Persyaratan UI umum adalah memiliki tata letak di mana elemen saling tumpang tindih. Biasanya padding, margin, penyelarasan, dan transformasi digunakan untuk memposisikan elemen dengan cara ini. Kontrol Kisi XAML dioptimalkan untuk meningkatkan performa tata letak untuk elemen yang tumpang tindih.

Penting Untuk melihat peningkatan, gunakan Kisi sel tunggal. Jangan tentukan RowDefinitions atau ColumnDefinitions.

Contoh

<Grid>
    <Ellipse Fill="Red" Width="200" Height="200" />
    <TextBlock Text="Test" 
               HorizontalAlignment="Center" 
               VerticalAlignment="Center" />
</Grid>

Text overlaid on a circle

<Grid Width="200" BorderBrush="Black" BorderThickness="1">
    <TextBlock Text="Test1" HorizontalAlignment="Left" />
    <TextBlock Text="Test2" HorizontalAlignment="Right" />
</Grid>

Two text blocks in a grid

Menggunakan properti batas bawaan panel

Kontrol Kisi, StackPanel, RelativePanel, dan ContentPresenter memiliki properti batas bawaan yang memungkinkan Anda menggambar batas di sekitarnya tanpa menambahkan elemen Batas tambahan ke XAML Anda. Properti baru yang mendukung batas bawaan adalah: BorderBrush, BorderThickness, CornerRadius, dan Padding. Masing-masing adalah DependencyProperty, sehingga Anda dapat menggunakannya dengan pengikatan dan animasi. Mereka dirancang untuk menjadi pengganti penuh untuk elemen Border terpisah.

Jika UI Anda memiliki elemen Batas di sekitar panel ini, gunakan batas bawaan sebagai gantinya, yang menyimpan elemen tambahan dalam struktur tata letak aplikasi Anda. Seperti disebutkan sebelumnya, ini bisa menjadi penghematan yang signifikan, terutama dalam kasus UI berulang.

Contoh

<RelativePanel BorderBrush="Red" BorderThickness="2" CornerRadius="10" Padding="12">
    <TextBox x:Name="textBox1" RelativePanel.AlignLeftWithPanel="True"/>
    <Button Content="Submit" RelativePanel.Below="textBox1"/>
</RelativePanel>

Menggunakan peristiwa SizeChanged untuk merespons perubahan tata letak

Kelas FrameworkElement mengekspos dua peristiwa serupa untuk merespons perubahan tata letak: LayoutUpdated dan SizeChanged. Anda mungkin menggunakan salah satu peristiwa ini untuk menerima pemberitahuan saat elemen diubah ukurannya selama tata letak. Semantik dari dua peristiwa berbeda, dan ada pertimbangan performa penting dalam memilih di antara mereka.

Untuk performa yang baik, SizeChanged hampir selalu menjadi pilihan yang tepat. SizeChanged memiliki semantik intuitif. Ini dinaikkan selama tata letak ketika ukuran FrameworkElement telah diperbarui.

LayoutUpdated juga dinaikkan selama tata letak, tetapi memiliki semantik global—dinaikkan pada setiap elemen setiap kali elemen diperbarui. Biasanya hanya melakukan pemrosesan lokal di penanganan aktivitas, dalam hal ini kode dijalankan lebih sering daripada yang diperlukan. Gunakan LayoutUpdated hanya jika Anda perlu mengetahui kapan elemen diposisi ulang tanpa mengubah ukuran (yang jarang terjadi).

Memilih antar panel

Performa biasanya bukan pertimbangan saat memilih antara masing-masing panel. Pilihan tersebut biasanya dibuat dengan mempertimbangkan panel mana yang menyediakan perilaku tata letak yang paling dekat dengan UI yang Anda terapkan. Misalnya, jika Anda memilih antara Grid, StackPanel , dan RelativePanel, Anda harus memilih panel yang menyediakan pemetaan terdekat dengan model mental implementasi Anda.

Setiap panel XAML dioptimalkan untuk performa yang baik, dan semua panel memberikan performa yang sama untuk UI serupa.