Udostępnij przez


Optymalizowanie układu XAML

ważne interfejsy API

Układ to proces definiowania struktury wizualnej interfejsu użytkownika. Podstawowym mechanizmem opisywania układu w języku XAML są panele, które są obiektami kontenera, które umożliwiają pozycjonowanie i rozmieszczanie w nich elementów interfejsu użytkownika. Układ może być kosztowną częścią aplikacji XAML — zarówno w przypadku użycia procesora CPU, jak i obciążenia pamięci. Poniżej przedstawiono kilka prostych kroków, które można wykonać, aby poprawić wydajność układu aplikacji XAML.

Zmniejsz strukturę układu

Największy wzrost wydajności układu wynika z uproszczenia hierarchicznej struktury drzewa elementów interfejsu użytkownika. Panele istnieją w drzewie wizualnym, ale są elementami strukturalnymi, a nie pikseli tworzących elementy, takie jak przycisk lub prostokąt . Uproszczenie drzewa przez zmniejszenie liczby elementów niezwiązanych z pikselami zwykle zwiększa wydajność.

Wiele interfejsów użytkownika jest implementowanych przez zagnieżdżanie paneli, co skutkuje głębokimi, złożonymi drzewami paneli i elementów. Zagnieżdżanie paneli jest wygodne, ale w wielu przypadkach ten sam interfejs użytkownika można uzyskać, używając bardziej złożonego pojedynczego panelu. Korzystanie z jednego panelu zapewnia lepszą wydajność.

Kiedy zmniejszyć strukturę układu

Zmniejszenie struktury układu w sposób trywialny — na przykład zmniejszenie jednego zagnieżdżonego panelu w twojej nadrzędnej stronie — nie ma zauważalnego efektu.

Największe wzrosty wydajności wynikają z zmniejszenia struktury układu powtarzającej się w interfejsie użytkownika, na przykład w ListView lub GridView. Elementy ItemsControl używają szablonu DataTemplate, który definiuje poddrzewo elementów interfejsu użytkownika, tworzone wiele razy. Kiedy to samo poddrzewo jest wielokrotnie duplikowane w aplikacji, wszelkie ulepszenia wydajności tego poddrzewa mają wielokrotne przełożenie na ogólną wydajność aplikacji.

Przykłady

Rozważmy następujący interfejs użytkownika.

przykład układu formularza

W tych przykładach przedstawiono 3 sposoby implementowania tego samego interfejsu użytkownika. Każdy wybór implementacji powoduje niemal identyczne piksele na ekranie, ale różni się znacznie w szczegółach implementacji.

Opcja1: zagnieżdżone elementy StackPanel

Chociaż jest to najprostszy model, używa 5 elementów panelu i powoduje znaczne obciążenie.

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

Opcja 2: Pojedyncza siatka

Grid zwiększa złożoność, ale używa tylko jednego elementu panelu.

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

Opcja 3. Pojedyncza RelativePanel:

Ten pojedynczy panel jest również nieco bardziej złożony niż używanie zagnieżdżonych paneli, ale może być łatwiejszy do zrozumienia i utrzymania niż 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>

Jak pokazano w tych przykładach, istnieje wiele sposobów osiągnięcia tego samego interfejsu użytkownika. Należy starannie rozważyć wszystkie kompromisy, w tym wydajność, czytelność i łatwość konserwacji.

Użyj siatki jednokomórkowej do nakładania się interfejsu użytkownika

Typowym wymaganiem interfejsu użytkownika jest układ, w którym elementy nakładają się na siebie. Zazwyczaj wypełnienie, marginesy, wyrównania i przekształcenia są używane do umieszczania tych elementów w ten sposób. Grid kontrolka XAML jest zoptymalizowana w celu poprawy wydajności układu dla elementów nakładających się na siebie.

Ważne Aby zobaczyć poprawę, użyj siatki z jedną komórką. Nie definiuj RowDefinitions ani ColumnDefinitions.

Przykłady

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

tekst nakładany na kółko

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

dwa bloki tekstowe w siatce

Używanie wbudowanych właściwości obramowania panelu

Grid, StackPanel, RelativePaneli ContentPresenter kontrolki mają wbudowane właściwości obramowania, które umożliwiają rysowanie obramowania bez dodawania dodatkowego elementu Border do kodu XAML. Nowe właściwości obsługujące wbudowane obramowanie to: BorderBrush, BorderThickness, CornerRadiusi Wypełnienie. Każdy z nich jest DependencyProperty, więc można ich używać z powiązaniami i animacjami. Są one zaprojektowane tak, aby były pełnym zamiennikiem oddzielnego elementu Border.

Jeśli Twój interfejs użytkownika ma elementy obramowania wokół tych paneli, użyj wbudowanego obramowania, które zapisuje dodatkowy element w strukturze układu aplikacji. Jak wspomniano wcześniej, może to być znaczne oszczędności, zwłaszcza w przypadku powtarzającego się interfejsu użytkownika.

Przykłady

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

Wykorzystaj zdarzenia SizeChanged, aby reagować na zmiany układu

Klasa FrameworkElement uwidacznia dwa podobne zdarzenia reagowania na zmiany układu: LayoutUpdated i SizeChanged. Możesz użyć jednego z tych zdarzeń, aby otrzymywać powiadomienia, gdy rozmiar elementu zostanie zmieniony podczas układu. Semantyka tych dwóch zdarzeń jest różna i istnieją ważne zagadnienia dotyczące wydajności podczas wybierania między nimi.

Aby uzyskać dobrą wydajność, SizeChanged jest niemal zawsze najlepszym wyborem. SizeChanged ma intuicyjną semantyką. Jest on zgłaszany podczas układu, gdy rozmiar FrameworkElement został zaktualizowany.

LayoutUpdated jest również zgłaszany podczas układu, ale ma semantykę globalną — jest wywoływane na każdym elemencie za każdym razem, gdy jakikolwiek element zostanie zaktualizowany. Zwykle przetwarzanie lokalne odbywa się tylko w programie obsługi zdarzeń, w tym przypadku kod jest uruchamiany częściej niż jest to konieczne. Używaj LayoutUpdated tylko wtedy, gdy trzeba wiedzieć, kiedy element jest przestawiany bez zmiany jego rozmiaru (co nie jest powszechne).

Wybieranie między panelami

Wydajność zazwyczaj nie jest brana pod uwagę podczas wybierania między poszczególnymi panelami. Wybór jest zazwyczaj dokonywany na podstawie tego, który panel zapewnia najbardziej zbliżone do wdrażanego interfejsu użytkownika zachowanie układu. Jeśli na przykład wybierasz między Grid, StackPanel i RelativePanel, powinieneś wybrać panel, który najlepiej odpowiada twojemu modelowi mentalnemu implementacji.

Każdy panel XAML jest zoptymalizowany pod kątem dobrej wydajności, a wszystkie panele zapewniają podobną wydajność dla podobnego interfejsu użytkownika.