Оптимизация макета XAMLOptimize your XAML layout

Важные APIImportant APIs

Определение макета — это процесс определения визуальной структуры для пользовательского интерфейса.Layout is the process of defining the visual structure for your UI. Базовым механизмом описания макета в XAML является определение с помощью панелей, представляющих собой объекты-контейнеры, в которых можно помещать и соответствующим образом располагать элементы пользовательского интерфейса.The primary mechanism for describing layout in XAML is through panels, which are container objects that enable you to position and arrange the UI elements within them. Макет может быть затратной частью приложения XAML как в плане загрузки ЦП, так и в плане использования памяти.Layout can be an expensive part of a XAML app—both in CPU usage and memory overhead. Ниже приведены несколько простых действий, которые можно выполнить для повышения производительности макета приложения XAML.Here are some simple steps you can take to improve the layout performance of your XAML app.

Уменьшение структуры макетаReduce layout structure

Максимального повышения производительности макета можно добиться путем упрощения иерархической структуры дерева элементов пользовательского интерфейса.The biggest gain in layout performance comes from simplifying the hierarchical structure of the tree of UI elements. Панели располагаются в визуальном дереве, однако они являются структурными элементами, а не элементами, увеличивающими количество пикселей, как, например, Button или Rectangle.Panels exist in the visual tree, but they are structural elements, not pixel producing elements like a Button or a Rectangle. Упрощение дерева путем уменьшения количества элементов, не увеличивающих количество пикселей, как правило, обеспечивает существенное повышение производительности.Simplifying the tree by reducing the number of non-pixel-producing elements typically provides a significant performance increase.

Многие пользовательские интерфейсы реализованы путем вложения панелей, что приводит к созданию сложных деревьев панелей и элементов.Many UIs are implemented by nesting panels which results in deep, complex trees of panels and elements. Вкладывать панели удобно, но во многих случаях точно такой же пользовательский интерфейс можно создать и с помощью одной более сложной панели.It is convenient to nest panels, but in many cases the same UI can be achieved with a more complex single panel. Использование только одной панели позволяет повысить производительность.Using a single panel provides better performance.

Когда следует уменьшать структуру макетаWhen to reduce layout structure

Уменьшение структуры макета обычным способом, например путем удаления одной вложенной панели из страницы верхнего уровня, не даст ощутимого эффекта.Reducing layout structure in a trivial way—for example, reducing one nested panel from your top-level page—does not have a noticeable effect.

Наиболее значительного увеличения производительности можно добиться за счет уменьшения структуры макета, которая повторяется в пользовательском интерфейсе, например в ListView или GridView.The largest performance gains come from reducing layout structure that's repeated in the UI, like in a ListView or GridView. Эти элементы ItemsControl используют шаблон DataTemplate, определяющий поддерево элементов пользовательского интерфейса, из которого многократно создаются экземпляры.These ItemsControl elements use a DataTemplate, which defines a subtree of UI elements that is instantiated many times. Если такое же поддерево много раз дублировать в приложении, то любые улучшения производительности окажут мультипликативный эффект на общую производительность приложения.When the same subtree is being duplicated many times in your app, any improvements to the performance of that subtree has a multiplicative effect on the overall performance of your app.

ПримерыExamples

Рассмотрите приведенный ниже пользовательский интерфейс.Consider the following UI.

Пример макета формы

В этих примерах показаны 3 способа реализации одного пользовательского интерфейса.These examples shows 3 ways of implementing the same UI. Каждый вариант реализации обеспечивает примерно одинаковое количество пикселей на экране, но существенно отличается в плане способа реализации.Each implementation choice results in nearly identical pixels on the screen, but differs substantially in the implementation details.

Вариант 1. Вложенные элементы StackPanelOption1: Nested StackPanel elements

Хотя это наиболее простая модель, в ней используются элементы с 5 панелями, что приводит к значительным дополнительным затратам.Although this is the simplest model, it uses 5 panel elements and results in significant overhead.

  <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. Отдельный элемент GridOption 2: A single Grid

Grid добавляет определенную сложность, но в этой модели используется элемент с одной панелью.The Grid adds some complexity, but uses only a single panel element.

<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. Отдельный элемент RelativePanelOption 3: A single RelativePanel:

Эта модель с одной панелью также немного более сложная, чем модель с использованием вложенных панелей, но она легче для понимания и обслуживания, чем Grid.This single panel is also a bit more complex than using nested panels, but may be easier to understand and maintain than a 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>

Как показывают эти примеры, существует много способов создания одного и того же пользовательского интерфейса.As these examples show, there are many ways of achieving the same UI. При выборе необходимо внимательно рассматривать все факторы, включая производительность, удобочитаемость и возможность поддержки.You should choose by carefully considering all the tradeoffs, including performance, readability, and maintainability.

Для накладывающихся пользовательских интерфейсов используйте сетки с одной ячейкойUse single-cell grids for overlapping UI

Общее требование к пользовательскому интерфейсу заключается в том, чтобы в макете элементы накладывались друг на друга.A common UI requirement is to have a layout where elements overlap each other. Как правило, для размещения элементов подобным образом используют заполнение, поля, выравнивание и преобразование.Typically padding, margins, alignments, and transforms are used to position the elements this way. Элемент управления XAML Grid оптимизирован для повышения производительности макета с накладывающимися элементами.The XAML Grid control is optimized to improve layout performance for elements that overlap.

Важно!   Чтобы добиться видимого улучшения, используйте элемент Grid с одной ячейкой.Important  To see the improvement, use a single-cell Grid. Не задавайте RowDefinitions или ColumnDefinitions.Do not define RowDefinitions or ColumnDefinitions.

ПримерыExamples

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

Два текстовых блока в сетке

Используйте свойства встроенной границы панелиUse a panel's built-in border properties

Элементы управления Grid, StackPanel, RelativePanel и ContentPresenter имеют свойства встроенной границы, позволяющие рисовать вокруг них границу без добавления дополнительного элемента Border.Grid, StackPanel, RelativePanel, and ContentPresenter controls have built-in border properties that let you draw a border around them without adding an additional Border element to your XAML. Новые свойства, поддерживающие встроенную границу: BorderBrush, BorderThickness, CornerRadius и Padding.The new properties that support the built-in border are: BorderBrush, BorderThickness, CornerRadius, and Padding. Каждое из этих свойств представляет собой DependencyProperty, в связи с чем их можно использовать с привязками и анимациями.Each of these is a DependencyProperty, so you can use them with bindings and animations. Они предназначены для того, чтобы служить полной заменой отдельного элемента Border.They’re designed to be a full replacement for a separate Border element.

Если ваш пользовательский интерфейс включает элементы Border вокруг этих панелей, используйте вместо них встроенную границу, которая позволит сэкономить место для дополнительного элемента в структуре макета вашего приложения.If your UI has Border elements around these panels, use the built-in border instead, which saves an extra element in the layout structure of your app. Как упоминалось ранее, это может обеспечить значительную экономию, особенно в случае повторяемых пользовательских интерфейсов.As mentioned previously, this can be a significant savings, especially in the case of repeated UI.

ПримерыExamples

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

Используйте события SizeChanged в случае изменения макетаUse SizeChanged events to respond to layout changes

Класс FrameworkElement предоставляет два аналогичных события для реагирования на изменения макета: LayoutUpdated и SizeChanged.The FrameworkElement class exposes two similar events for responding to layout changes: LayoutUpdated and SizeChanged. Вы можете использовать одно из этих событий для получения уведомлений об изменении размера элемента во время редактирования макета.You might be using one of these events to receive notification when an element is resized during layout. Семантика этих двух событий отличается, и при выборе одного из них важно учитывать производительность.The semantics of the two events are different, and there are important performance considerations in choosing between them.

Для обеспечения высокой производительности почти всегда лучше выбирать SizeChanged.For good performance, SizeChanged is almost always the right choice. Событие SizeChanged имеет интуитивную семантику.SizeChanged has intuitive semantics. Оно возникает во время редактирования макета в случае изменения размера FrameworkElement.It is raised during layout when the size of the FrameworkElement has been updated.

Событие LayoutUpdated также возникает при редактировании макета, но при этом оно имеет глобальную семантику, так как возникает при изменении любого элемента.LayoutUpdated is also raised during layout, but it has global semantics—it is raised on every element whenever any element is updated. Это событие, как правило, выбирают только для локальной обработки в обработчике событий; и в этом случае код запускается чаще, чем это необходимо.It is typical to only do local processing in the event handler, in which case the code is run more often than needed. Используйте LayoutUpdated только в том случае, если вам необходимо получать уведомление о перемещении элемента без изменения размера (что происходит нечасто).Use LayoutUpdated only if you need to know when an element is repositioned without changing size (which is uncommon).

Выбор панелейChoosing between panels

Производительность, как правило, не учитывается при выборе панели.Performance is typically not a consideration when choosing between individual panels. Этот выбор обычно делается на основании того, какая из панелей обеспечивает поведение макета, наиболее близкое к пользовательскому интерфейсу, который вы реализуете.That choice is typically made by considering which panel provides the layout behavior that is closest to the UI you’re implementing. Например, если выбирать между Grid, StackPanel и RelativePanel, следует отдать предпочтение той панели, которая обеспечивает наиболее точное сопоставление с задуманной вами моделью реализации.For example, if you’re choosing between Grid, StackPanel , and RelativePanel, you should choose the panel that provides the closest mapping to your mental model of the implementation.

Каждая панель XAML оптимизирована для обеспечения высокой производительности, и все панели обеспечивают одинаковую производительность для аналогичных пользовательских интерфейсов.Every XAML panel is optimized for good performance, and all the panels provide similar performance for similar UI.