UI大小调整导致巨大的CPU负载

本文关键字:巨大 CPU 负载 调整 UI | 更新日期: 2023-09-27 18:11:29

我最近一直在开发一个RTF编辑器,这只是一个简单的UserControl,它有一个RichTextBox与一对事件,如PreviewTextInputPreviewMouseUp

我注意到一些有点烦人的事情。当UI被调整大小时,RichTextBox的性能是绝对糟糕的,RichTextBox有很多文本导致它的换行算法着火。

这会给应用程序一种非常草率的感觉,就好像它优化得很差(即使它不是)。

起初,我注意到在选择文本时性能受到影响,所以我决定使用PreviewMouseUp事件,而不是使用SelectionChanged事件,然后获取选择。

然后经过进一步的测试,我发现调整大小也造成了巨大的负载。我说的是负载在5% -> 30%之间,四核CPU运行在3.8GHz!

为了进一步测试它,我决定注释掉我的RichTextBox,只包含一个没有定义属性的新RichTextBox

<RichTextBox/>

将其插入窗口,填充文本,然后调整窗口大小,使换行算法再次执行相同操作,使用率高达30% !

我试着研究这个问题,大多数人最终建议将PageWidth设置为高值,以防止换行:

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

这是我不想要的,因为我写的上一个版本的编辑器是用WinForms制作的,可以毫不费力地进行包装,我也希望在新的WPF版本中使用它。

还有人遇到过这个问题吗?如果是,你能给我指出正确的方向,以消除对硬件的巨大压力吗?

我有点难过,因为我喜欢WPF,但我确实发现一个或另一个对象,是真正未优化和/或不实用的与WinForms相比,RichTextBox似乎是另一种情况:(

很抱歉有这么多的文字,但我真的很想把这个整齐地记录下来,以防其他可怜的人面临这个问题,让你们看看我到目前为止所做的努力。

UI大小调整导致巨大的CPU负载

克服这个问题的一种方法可能是在窗口调整大小时切换到"无换行"模式,但当用户完成调整大小时,切换回正常模式。然后包装算法将在最后只执行一次,用户应该仍然对你的应用程序有流畅的感觉。示例代码:

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