UltravioletFramework / ultraviolet

The Ultraviolet Framework is a .NET game development framework written in C#.
https://github.com/UltravioletFramework/ultraviolet/wiki
MIT License
541 stars 46 forks source link

UPF becomes unresponsive/sluggish when adding a fair bit of text to a text box that has wrapping. #131

Closed fireball87 closed 4 years ago

fireball87 commented 4 years ago

I have a read only textbox in UPF that is created via

<TextBox Name="chatTextBox" TextWrapping="Wrap" Grid.Row="0" Grid.Column="0" VerticalScrollBarVisibility="Visible" IsReadOnly="True"></TextBox>

I add to it using the code

private void addChatText(string text)
            {
                bool scrolledToBottom = chatTextBox?.VerticalOffset > chatTextBox?.ExtentHeight - chatTextBox?.ViewportHeight - 50;
                chatTextBox?.AppendText(text + "\n");
                if (scrolledToBottom)
                {
                    chatTextBox?.ScrollToEnd();
                }
            }

For my system info, Manjaro Linux running KDE Dotnet Core 3.1

When I add a bunch of lines that need wrapped things become VERY slow and problematic entering text, If i destroy the textbox everything becomes fast again, and this doesn't happen without the wrapping. This is pretty hard to capture in video, but I have made one. My current workaround is to not use text wrapping, which is fine.

https://www.youtube.com/watch?v=FzdgWf5BoyM&feature=youtu.be

Donaut commented 4 years ago

I think TextBox doesn't support virtualization.

What is Virtualization? Virtualization technique in WPF improves the rendering performance of UI elements. By applying virtualization, the layout system ensures that only the visible items of a container are rendered on the screen. For example, a list control may have thousands of items but virtualization will reduce the rendering to the visible items only.

The Solution to this is to use the ListBox control.

fireball87 commented 4 years ago

I think in the somewhat short run you're probably right and I should convert it, it also would make certain styling far easier, I'll throw it on my todo list.

Donaut commented 4 years ago

Help1

What is happening here is that the ListBox control has an ItemSource property you can see i created a dummy list named List in the ViewModel class and assigned it. The second necessary property is the ViewModelType it needs two parameters. The first one is the namespace (the namespace plus the class name) the second parameter is the actual solution name or assembly name call you as you like it.

Help3

Donaut commented 4 years ago

If you have a simple string array like this Screenshot_2

You can leave out the ItemTemplate part and end up with this. Screenshot_1 .

fireball87 commented 4 years ago

Yeah, I'm actually using listboxes for a couple elements already, so i had already mostly figured out data-templates (couple user lists, and then on the screen prior to this a list of games). Thanks for taking the time to produce such an example though.

I'm probably going to leave this open, as I assume the speed the element becomes unresponsive is still in bug territory (well under a page of text), that said I have a solution for my current uses, so feel free to close it if it's not worth persuing.

tlgkccampbell commented 4 years ago

I would expect appending text to get a bit slow before very long, since the entirety of the TextBox's content is laid out as a single unit. Ultraviolet isn't a text editor, so the reality is that its multi-line TextBox control is probably never going to work well with massive strings of dynamically changing text. However, there's probably room for further optimization here, so I'll look into it.

What does surprise me is that it gets so slow when just rendering the text. I suspect I know what the problem is, though, so I'll look into speeding that up for you.

I agree that for your use case, something other than TextBox is probably the correct choice, potentially even something custom.

tlgkccampbell commented 4 years ago

Commit c9d93652c502449e0512fde09149cb983cb61038 changes how text inside of a TextEditor control is clipped, which should improve rendering performance for very long strings.

tlgkccampbell commented 4 years ago

I've committed some micro-optimizations for text layout, but now that I've spent some time looking into this, I think that properly supporting very large strings of text is going to require fundamentally rearchitecting the text layout engine. Reworking fonts and text layout is something I've wanted to do for a while, but it's not currently a priority, I'm afraid.

For now, my recommendation is to use TextBox and PasswordBox only for relatively short strings, and to prefer custom solutions for use cases which require large amounts of text or text which changes frequently.