Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Основные API
Макет — это процесс определения визуальной структуры пользовательского интерфейса. Основной механизм описания макета в XAML — это панели, которые являются объектами контейнеров, которые позволяют размещать и упорядочивать элементы пользовательского интерфейса в них. Макет может быть ресурсоёмкой частью приложения XAML как по использованию ЦП, так и по нагрузке на память. Ниже приведены некоторые простые шаги, которые можно предпринять для повышения производительности макета приложения XAML.
Уменьшение структуры макета
Наибольшее повышение производительности макета происходит от упрощения иерархической структуры дерева элементов пользовательского интерфейса. Панели существуют в визуальном дереве, но они являются структурными элементами, а не элементами, которые производят пиксели, такими как кнопка или прямоугольник. Упрощение дерева путем уменьшения числа элементов, не являющихся пиксельными элементами, обычно обеспечивает значительное увеличение производительности.
Многие пользовательские интерфейсы реализуются вложенными панелями, что приводит к разветвлённым, сложным деревьям панелей и элементов. Удобно использовать вложенные панели, но во многих случаях тот же пользовательский интерфейс можно достичь с одной более сложной панелью. Использование одной панели обеспечивает лучшую производительность.
Когда уменьшить структуру макета
Сокращение структуры макета в тривиальном способе, например сокращение одной вложенной панели с страницы верхнего уровня, не имеет заметного эффекта.
Наибольшее повышение производительности достигается от уменьшения структуры макета, повторяющейся в пользовательском интерфейсе, например в ListView или GridView. Эти элементы ItemsControl используют DataTemplate, которая определяет поддерево элементов пользовательского интерфейса, инстанцируемое много раз. При многократном дублировании одного и того же поддерева в вашем приложении любые улучшения производительности этого поддерева оказывают мультипликативный эффект на общую производительность вашего приложения.
Примеры
Рассмотрим следующий пользовательский интерфейс.
Пример макета формы
В этих примерах показаны 3 способа реализации одного пользовательского интерфейса. Каждый выбор реализации приводит к почти идентичным пикселям на экране, но существенно отличается в деталях реализации.
Вариант 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:
Эта одна панель также является немного более сложной, чем использование вложенных панелей, но может быть проще понимать и поддерживать, чем Сетка.
<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>
Как показано в этих примерах, существует множество способов достижения одного пользовательского интерфейса. Необходимо тщательно рассмотреть все компромиссы, включая производительность, удобочитаемость и удобство обслуживания.
Использование сетки с одной ячейкой для перекрывающегося пользовательского интерфейса
Обычное требование пользовательского интерфейса заключается в наличии макета, в котором элементы пересекаются друг с другом. Обычно для размещения элементов таким образом используются отступы, поля, выравнивания и преобразования. Элемент управления сетки 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>
Использование встроенных свойств границы панели
Сетка, StackPanel, RelativePanel, и ContentPresenter имеют встроенные свойства границы, которые позволяют создавать границы вокруг них, не добавляя в XAML дополнительный элемент Border. Новые свойства, поддерживающие встроенную границу: BorderBrush, BorderThickness, CornerRadiusи padding. Каждый из них — это DependencyProperty , поэтому их можно использовать для привязки и анимации. Они предназначены для полной замены отдельного элемента Border.
Если в пользовательском интерфейсе есть элементы Border вокруг этих панелей, используйте встроенную границу, которая сохраняет дополнительный элемент в структуре макета приложения. Как упоминалось ранее, это может быть значительной экономией, особенно в случае повторения пользовательского интерфейса.
Примеры
<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 только в том случае, если необходимо знать, когда элемент перемещается без изменения размера (что редко).
Выбор между панелями
Производительность обычно не учитывается при выборе между отдельными панелями. Этот выбор обычно делается с учетом того, какая панель предоставляет поведение макета, ближайшее к реализуемому пользовательскому интерфейсу. Например, если вы выбираете между сеткой , StackPanel и RelativePanel , вы должны выбрать панель, которая обеспечивает ближайшее сопоставление с вашей ментальной моделью реализации.
Каждая панель XAML оптимизирована для хорошей производительности, и все панели обеспечивают аналогичную производительность для аналогичного пользовательского интерфейса.