AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
24.57k stars 2.12k forks source link

DataGrid performance on attached to visual tree. #16139

Closed IZIDIA closed 4 hours ago

IZIDIA commented 1 week ago

Describe the bug

Hello. I'm using a DataGrid in my project and have noticed a performance hit when my table is attached to a visual tree. I ran a dotTrace measurement inside the Rider IDE and noticed that the InitializeElements method was taking a long time.

The commit that was made earlier solves one of the problems: https://github.com/AvaloniaUI/Avalonia/issues/9527

pull: https://github.com/almightyju/Avalonia/commit/e9f2cb34789017b0db57e33d02660c2bc70af4bf

But I believe there is a bug in this commit.

InitializeElements(bool recycleRows) now we use false.

This leads to the fact that every time we connect to the visual tree, we build the columns in the table all over again. But at the same time, we only need to update the rows. We need use only RefreshRows inside method InitializeElements(bool recycleRows).

And so we must replace this:

        protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
        {
            base.OnAttachedToVisualTree(e);
            if (DataConnection.DataSource != null && !DataConnection.EventsWired)
            {
                DataConnection.WireEvents(DataConnection.DataSource);
                InitializeElements(false /*recycleRows*/);
            }
        }

TO:

        protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
        {
            base.OnAttachedToVisualTree(e);
            if (DataConnection.DataSource != null && !DataConnection.EventsWired)
            {
                DataConnection.WireEvents(DataConnection.DataSource);
                InitializeElements(true /*recycleRows*/);
            }
        }

My measurements using Stopwatch (I was just switching between tabs):

   protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
        {
            base.OnAttachedToVisualTree(e);
            if (DataConnection.DataSource != null && !DataConnection.EventsWired)
            {
                DataConnection.WireEvents(DataConnection.DataSource);
                var timer = new Stopwatch();
                timer.Start();
                InitializeElements(false /*recycleRows*/);
                timer.Stop();
                Debug.WriteLine(timer.Elapsed);
            }
        }

InitializeElements(false /*recycleRows*/);

00:00:01.5716088
00:00:01.8027466
00:00:01.4541749
00:00:01.6555272
00:00:01.6144568

InitializeElements(true /*recycleRows*/);

00:00:00.1817455
00:00:00.1990262
00:00:00.1896094
00:00:00.2103093
00:00:00.1970060

To Reproduce

Open the ready-made DataGrid examples in the avalonia project and start switching between tabs.

Expected behavior

No response

Avalonia version

11.1-rc1

OS

Windows

Additional context

No response

IZIDIA commented 1 week ago

By the way. Removing the InitializeElements(false /*recycleRows*/); line completely solves the scrolling problem. When you switch to another tab and back. Your scrolling position remains in the same place. I plan to spend some more time solving this problem.

See #15218

IZIDIA commented 1 week ago

This should solve both problems. https://github.com/AvaloniaUI/Avalonia/pull/16140