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;
}
ベンチマークは、フォーマット()はわずかに速くオフスクリーンレンダリングを実行することを示しているが、体感的なパフォーマンスは、今でも悪いです。だから私はいくつかのダブルバッファリングを試してみました!
これについては適切な方法はありますか?
こんにちはリチャード、 あなたはこれに対処したことがありますか? WPF RichTextBoxで同様の問題が発生しています。 Alan –
私の3回目の試みは次のようなものでした:(1)キーストロークでドキュメント(2)のXAML表現を管理する長時間実行するバックグラウンドスレッドを作成し、適切な停止ポイントを押し、修正されたXAMLをUIスレッドにポストし、TextRange.Load()を実行するたびに、XAMLドキュメントを手動で操作する(FlowDocumentではなく文字列解析を使用する)(4)これははるかに優れていましたが、それでも素晴らしいことはありません。私がまだプロジェクトについて気にしていたのであれば、VSがそれをどのようにしているか見るためにReflectorを覗いてみました:) –