WPF:将格式应用于RichTextBox的快速方法

时间:2009-08-17 16:14:05

标签: wpf performance formatting richtextbox syntax-highlighting

我正在尝试在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]);
    }
}

在一个只有100多个令牌的2KB文档上进行测试,每次击键后需要1-2秒才能重绘;显然不能接受。分析表明我的tokenizer比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()在屏幕外渲染的速度稍快,但感知性能现在更差!

正确的方法是什么?

1 个答案:

答案 0 :(得分:1)

我尝试尽可能多地从方法/循环中获取对象实例化,然后传入引用。每次按键每次循环都会调用新的几次。