【问题标题】:WPF: fast way to apply formatting to RichTextBoxWPF:将格式应用于 RichTextBox 的快速方法
【发布时间】:2010-11-20 07:25:00
【问题描述】:

我正在尝试在 WPF RichTextBox 中显示基本语法突出显示。它主要工作,但渲染性能很糟糕。

首先我天真地尝试过:

/// <summary>
/// Main event handler for syntax highlighting.
/// </summary>
private void XmlChanged(object sender, TextChangedEventArgs e)
{
    VM.Dirty = true;
    if (VM.Pretty)
    {
        var range = new TextRange(XmlView.Document.ContentStart, XmlView.Document.ContentEnd);
        Render(range.Text);
    }
}

/// <summary>
/// Entry point for programmatically resetting the textbox contents
/// </summary>
private void Render(string text)
{
    XmlView.TextChanged -= this.XmlChanged;

    if (VM.Pretty)
    {
        var tokens = tokenizer.Tokenize(text);
        Format(XmlView.Document, tokens);
    }

    XmlView.TextChanged += this.XmlChanged;     
}

private void Format(FlowDocument doc, List<Token> tokens)
{
    var start = doc.ContentStart;
    foreach (var token in tokens)
    {
        TextRange range = new TextRange(start.GetPositionAtOffset(token.StartPosition, LogicalDirection.Forward),
                                        start.GetPositionAtOffset(token.EndPosition, LogicalDirection.Forward));
        range.ApplyPropertyValue(TextElement.ForegroundProperty, m_syntaxColors[token.Type]);
    }
}

在一个 2KB 的文档上进行测试,其中只有 100 多个标记,每次击键后重绘需要 1-2 秒;显然不能接受。分析表明,我的标记器比 Format() 函数快几个数量级。所以我尝试了一些双缓冲:

private void Render(string text)
{
    XmlView.TextChanged -= this.XmlChanged;

    // create new doc offscreen
    var doc = new FlowDocument();
    var range = new TextRange(doc.ContentStart, doc.ContentEnd);
    range.Text = text;

    if (VM.Pretty)
    {
        var tokens = tokenizer.Tokenize(text);
        Format(doc, tokens);
    }

    // copy to active buffer
    var stream = new MemoryStream(65536);
    range.Save(stream, DataFormats.XamlPackage);
    var activeRange = new TextRange(XmlView.Document.ContentStart, XmlView.Document.ContentEnd);
    activeRange.Load(stream, DataFormats.XamlPackage);

    XmlView.TextChanged += this.XmlChanged;     
}

基准测试显示 Format() 在屏幕外渲染时运行速度稍快,但现在感知到的性能更差!

解决这个问题的正确方法是什么?

【问题讨论】:

  • 嗨,理查德,您有没有为此找到解决方案?我在使用 WPF RichTextBox 时遇到了类似的问题。最好的问候,艾伦
  • 我的第三次尝试是这样的:(1) 创建一个长时间运行的后台线程,该线程管理自己的文档的 XAML 表示 (2) 在击键时,发布到另一个线程所在的队列观看 (3) 出队时,手动操作 XAML 文档(即使用字符串解析,而不是 FlowDocument) (4) 每当您遇到一个好的停止点时,将修改后的 XAML 发布回 UI 线程并执行 TextRange.Load()。这表现得更好,但仍然不是很好。如果我仍然关心这个项目,我会在 Reflector 中四处寻找,看看 VS 是如何做到的 :)

标签: wpf performance formatting richtextbox syntax-highlighting


【解决方案1】:

我会尝试尽可能多地从方法/循环中取出对象实例化,并改为传递引用。每次按键循环,您都会调用 new 很多次。

【讨论】:

  • 不幸的是,TextRange 类的 Start 和 End 属性是只读的。我发现在每次迭代中表示正确范围的唯一方法是创建新的。
猜你喜欢
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多