#performance #layout #uwp #grid
#Производительность #макет #uwp #сетка
Вопрос:
У меня есть сетка внутри ListBox в моем приложении UWP C #. С маленькой сеткой проблем нет. Однако, когда сетка содержит более 50 ячеек с несколькими строками и столбцами, удаление сетки из родительского элемента происходит очень медленно. Это занимает более 1 минуты или около 2 минут. Я пытался скрыть это, изменив его видимость на свернутую или непрозрачность на 0 или создав исполняемый файл выпуска, но все равно слишком медленно, как и раньше. ToList().Clear() в некоторых случаях работает быстро, но недостаточно.
ListBox rootBox = new ListBox();
rootBox.Items.Add(grid); // adding a complex Grid with over 50 cells with inner UI elements like TextBlock, TextBox and so on.
rootBox.Items.Remove(grid); <--- takes about 2 minutes with CPU utilization under 15% in my modern PC
В UWP нет API для приостановки и возобновления обновления макета.
Динамическое управление элементом сетки UWP кажется мне непрактично медленным.
Я пытался найти способ оптимизировать производительность для пользовательского интерфейса Grid, но потерпел неудачу.
Профилирование показало мне, что задача компоновки занимает около 50% процессора процесса, но не интенсивно даже в 1 ядре. Это означает, что медлительность не связана с вычислениями, требующими больших затрат процессора.
О, я попытался упростить проблему и нашел дело. Сетка внутри нескольких вложенных списков! Вложение большего количества списков замедляет работу программы. Вы можете воспроизвести случай, нажав нижнюю кнопку «Очистить» программы ниже. Код воспроизведения:
—————— MainPage.xaml ——————
<Page
x:Class="GridSlow.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:GridSlow"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Loaded="OnLoaded_Page"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Name="rootGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Visible" Grid.Row="0">
<ListBox Name="innerList">
</ListBox>
</ScrollViewer>
<Button Content="Clear" Click="Button_Click" Grid.Row="1"/>
</Grid>
</Page>
———————— MainPage.xaml.cs ————————
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace GridSlow
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void OnLoaded_Page(object sender, RoutedEventArgs args)
{
Grid grid = new Grid();
for (int row = 0; row < 50; row)
{
RowDefinition rowDef = new RowDefinition();
rowDef.Height = new GridLength(0, GridUnitType.Auto);
rowDef.MinHeight = 10;
grid.RowDefinitions.Add(rowDef);
for (int col = 0; col < 2; col)
{
ColumnDefinition colDef = new ColumnDefinition();
colDef.Width = new GridLength(0, GridUnitType.Auto);
colDef.MinWidth = 10;
grid.ColumnDefinitions.Add(colDef);
Border border = new Border() { BorderBrush = new SolidColorBrush(Colors.DarkGray), BorderThickness = new Thickness(1) };
TextBox textBox = new TextBox();
textBox.Text = "aaa";
border.Child = textBox;
grid.Children.Add(border);
Grid.SetRow(border, row);
Grid.SetColumn(border, col);
}
}
ListBox list2 = new ListBox();
ListBox list3 = new ListBox();
ListBox list4 = new ListBox();
ListBox list5 = new ListBox();
ListBox list6 = new ListBox();
TextBox box2 = new TextBox();
box2.Margin = new Thickness(1);
list2.Items.Add(box2);
list2.Items.Add(list3);
list3.Items.Add(new TextBox());
list3.Items.Add(list4);
list4.Items.Add(list5);
list5.Items.Add(list6);
list6.Items.Add(grid);
innerList.Items.Add(list2);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
innerList.Items.Clear();
}
}
}
Комментарии:
1. Я не могу воспроизвести вашу проблему. Не могли бы вы предоставить подробный код?
2. Я добавил код воспроизведения. Спасибо за проявленный интерес.
Ответ №1:
В вашем макете есть список с именем innerList со сложным элементом, Listbox2 вложен в элемент, а текстовое поле и ListBox3 вложены в ListBox2, что является еще одним сложным макетом. Это бессмысленное вложение элементов управления.
Эта многоуровневая вложенность приводит к тому, что разработчик тратит много времени на рендеринг. Поэтому, когда вы очищаете элементы, макет будет загружаться очень медленно.
Пожалуйста, удалите ненужную вложенность элементов управления, как показано ниже.
private void OnLoaded_Page(object sender, RoutedEventArgs args)
{
Grid grid = new Grid();
for (int row = 0; row < 50; row)
{
RowDefinition rowDef = new RowDefinition();
rowDef.Height = new GridLength(0, GridUnitType.Auto);
rowDef.MinHeight = 10;
grid.RowDefinitions.Add(rowDef);
for (int col = 0; col < 2; col)
{
ColumnDefinition colDef = new ColumnDefinition();
colDef.Width = new GridLength(0, GridUnitType.Auto);
colDef.MinWidth = 10;
grid.ColumnDefinitions.Add(colDef);
Border border = new Border() { BorderBrush = new SolidColorBrush(Colors.DarkGray), BorderThickness = new Thickness(1) };
TextBox textBox = new TextBox();
textBox.Text = "aaa";
border.Child = textBox;
grid.Children.Add(border);
Grid.SetRow(border, row);
Grid.SetColumn(border, col);
}
}
innerList.Items.Add(grid);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
innerList.Items.Clear();
}
Комментарии:
1. Вместо этого я заменил ListBox на StackPanel. Теперь это работает очень быстро!
2. Добавление текстового поля 1100 в макет сетки через grid. Дочерние элементы. Добавление занимает около 10 секунд. Есть ли какой-либо способ оптимизировать производительность в UWP?
3. @HeeSuKim Каждое из ваших текстовых полей имеет границу родительского элемента управления. Я предлагаю удалить границу.