Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
174 views
in Technique[技术] by (71.8m points)

performance - Removing a UWP Grid is too slow

I have a Grid inside ListBox in my UWP C# application. There is no problem with small grid. However, when a Grid has over 50 cells with multiple rows and columns, removing the grid from its parent is very slow. It takes over 1 minute or about 2 minutes. I tried to hide it by changing its Visibility to Collapsed or Opacity to 0 or building a release executable but still too slow as the same. ToList().Clear() works fast in some case, but not enough.

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

There's no APIs to suspend and resume layout update in UWP.

Dynamically manipulating a UWP Grid element seems unpractically slow to me.

I tried to find a way to optimize performance for Grid UI, but failed.

Profiling showed me that layout task takes about 50% of CPU of the process but not intensive even in 1 core. It means the slowness is not from CPU-intensive calculation.


Oh, I tried to simplify the problem and found the case. A grid inside multiple nested ListBoxes! Nesting more ListBox makes the program slower. You could reproduce the case by clicking the bottom 'Clear' button of the program below. Reproduction code:

------------------ 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();
        }
    }
}
question from:https://stackoverflow.com/questions/65859296/removing-a-uwp-grid-is-too-slow

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your layout has a ListBox named innerList with a complex item, Listbox2 is nested in the item, and a textbox and ListBox3 are nested in the ListBox2, which is another complex layout. This is meaningless control nesting.

This multi-level nesting causes that the designer spends a long time on rendering. So when you clear the Items, the layout will load very slowly.

Please remove unnecessary control nesting like the following.

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();
    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...