2009-08-17 12 views
4

WPFリッチテキストボックスで基本的な構文ハイライトを表示しようとしています。主に動作しますが、レンダリングのパフォーマンスはひどいです。WPF:リッチテキストボックスに書式を適用する速い方法

私は単純に最初に試した:

/// <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個のトークンと2キロバイトの文書には、それはすべてのキーストロークの後に再描画するために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;  
} 

ベンチマークは、フォーマット()はわずかに速くオフスクリーンレンダリングを実行することを示しているが、体感的なパフォーマンスは、今でも悪いです。だから私はいくつかのダブルバッファリングを試してみました!

これについては適切な方法はありますか?

+0

こんにちはリチャード、 あなたはこれに対処したことがありますか? WPF RichTextBoxで同様の問題が発生しています。 Alan –

+0

私の3回目の試みは次のようなものでした:(1)キーストロークでドキュメント(2)のXAML表現を管理する長時間実行するバックグラウンドスレッドを作成し、適切な停止ポイントを押し、修正されたXAMLをUIスレッドにポストし、TextRange.Load()を実行するたびに、XAMLドキュメントを手動で操作する(FlowDocumentではなく文字列解析を使用する)(4)これははるかに優れていましたが、それでも素晴らしいことはありません。私がまだプロジェクトについて気にしていたのであれば、VSがそれをどのようにしているか見るためにReflectorを覗いてみました:) –

答えて

1

可能な限り多くのオブジェクトのインスタンス化をメソッド/ループから取り除き、代わりに参照を渡してみます。キーストロークごとにループごとにかなり新しく呼びます。

+0

残念ながら、TextRangeクラスのStartおよびEndプロパティは読み取り専用です。私が各反復で正しい範囲を表すために見つけた唯一の方法は、新しい反復を作成することです。 –

関連する問題