2009-08-17 64 views
4

我試圖在WPF RichTextBox中顯示基本的語法高亮顯示。它主要工作,但渲染性能很糟糕。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秒後,每個按鍵重繪;顯然不能接受。分析表明我的標記器比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

Hi Richard, 您是否曾經爲此解決過問題?我遇到類似WPF RichTextBox的問題。 祝好, Alan – 2010-07-09 09:04:51

+0

我的第三次嘗試是這樣的:(1)創建一個長時間運行的後臺線程,在按鍵時管理它自己的文檔(2)的XAML表示,發佈到另一個線程觀看(3)出列,手動操作XAML文檔(即使用字符串解析,而不是FlowDocument)(4),每當你遇到一個好的停止點時,將修訂後的XAML發回UI線程並執行TextRange.Load()。這表現好得多,但仍然不是很好。如果我仍然關心這個項目,我會在Reflector中查看它是如何執行的:) – 2010-07-10 04:50:59

回答

1

我試着儘可能多地從方法/循環中取出對象實例,然後傳入引用。每次按鍵每循環呼叫新的次數不少於幾次。

+0

不幸的是,TextRange類的Start和End屬性是隻讀的。只有在每次迭代中發現代表正確範圍的方法是創建新範圍。 – 2009-08-24 14:39:15