Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RichTextBox - UI Resize causes huge CPU Load

Tags:

c#

wpf

xaml

I've recently been developing an RTF Editor which is only a simple UserControl that has a RichTextBox with a couple Events like PreviewTextInput and PreviewMouseUp.

I noticed something slightly annoying though. The Performance of the RichTextBox is absolutely terrible whenever the UI is being resized and the RichTextBox has a lot of Text to cause its Wrapping Algorithm to fire.

This gives the Application a really sloppy feel, as if it is poorly optimized (even though it isn't).

At first I noticed this performance hit while selecting Text, so instead of using the SelectionChanged event, I decided to use the PreviewMouseUp event and then fetch the Selection.

Then after further testing I found out that the resize also caused huge loads. And I'm talking about loads ranging between 5% -> 30% with a Quad-Core CPU running at 3.8GHz!

To further test it out, I decided to comment out my RichTextBox and only include a new RichTextBox with no defined Property

<RichTextBox/>

Inserting this into a Window, filling with Text, and then resizing the Window to cause the Wrapping Algorithm did the same again, up to 30% usage!

I tried to research about this matter, and most people ended up recommending setting the PageWidth to high values in order to prevent Wrapping:

richTextBox1.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
richTextBox1.Document.PageWidth = 1000;

Which I do not want, since the previous Version of the Editor I wrote was made with WinForms and could do Wrapping effortlessly, and I also want it in the new WPF Version.

Did anyone else ever face this issue? If yes, could you please point me into the right direction to remove this huge strain on the hardware?

I'm a bit sad because I love WPF, but I did find one or the other Object that is really unoptimized and/or not practical in comparison to the WinForms counterpart, the RichTextBox seems to be another one of those cases :(

Sorry for the huge amount of Text, but I really wanted to Document this neatly in case some other poor soul faces this issue and for you guys to see what I've tried so far.

like image 632
Steven Borges Avatar asked Oct 04 '16 10:10

Steven Borges


1 Answers

One way to overcome this issue might be to switch to "no wrap" mode when window is being resized, but when user finished with resizing - switch back to normal mode. Then wrapping algorithm will be executed just once at the end and users should still have smooth feeling about your application. Sample code:

public partial class MainWindow : Window
{
    public MainWindow() {
        InitializeComponent();
        this.SizeChanged += OnSizeChanged;
    }

    private Timer _timer;
    private void OnSizeChanged(object sender, SizeChangedEventArgs e) {
        // user started resizing - set large page width
        textBox.Document.PageWidth = 1000;
        // if we already setup timer - stop it and start all over
        if (_timer != null) {
            _timer.Dispose();
            _timer = null;
        }

        _timer = new Timer(_ => {
            // this code will run 100ms after user _stopped_ resizing
            Dispatcher.Invoke(() =>
            {
                // reset page width back to allow wrapping algorithm to execute
                textBox.Document.PageWidth = double.NaN;
            });
        }, null, 100, Timeout.Infinite);
    }
}
like image 99
Evk Avatar answered Oct 19 '22 05:10

Evk