WPF 開發,優化 AvalonEdit 顯示單行超長文本的性能。
- 2022 年 3 月 2 日
- 筆記
- AvalonEdit, WPF, 開發, 路遙工具箱
路遙工具箱內置了一個名為「JSON 格式化」的功能。通過該功能可以將 JSON 字符串進行美化和簡化(設置縮進和取消縮進)。
該功能上線後收到很多客戶的反饋:大部分經由網絡傳輸的JSON消息都是未縮進的,在嘗試使用JSON美化工具對其進行加載時發生了卡死的情況。經筆者實測:一個兩兆左右的 JSON 文件需要三分鐘左右去渲染。
在展示單行超長文本時,包括 Visual Studio、Notpad2 在內的軟件表現都不盡人意。卡頓在加載和拖動時都會發生,特別是需要自動折行的時候。
原生的 TextBox 控件在面對這麼長的單行文本時也會出現卡頓。如果取消自動折行(設置 WrapText 為 False)可以改善這種情況。AvalonEdit 支持調整折行顯示,但仍舊需要較長的時間去渲染。
使用 TruncateLongLines 改善這個情況
經過一番探索,筆者在官方 GitHub 倉庫中找到了一個相關的 Issues ,Performance issue with word wrap ://github.com/icsharpcode/AvalonEdit/issues/11 。其中提到了一個名為 TruncateLongLines 的類型:
public class TruncateLongLines : VisualLineElementGenerator
{
const int maxLength = 2000;
const string ellipsis = "...";
const int charactersAfterEllipsis = 100;
public override int GetFirstInterestedOffset(int startOffset)
{
DocumentLine line = CurrentContext.VisualLine.LastDocumentLine;
if (line.Length > maxLength) {
int ellipsisOffset = line.Offset + maxLength - charactersAfterEllipsis - ellipsis.Length;
if (startOffset <= ellipsisOffset)
return ellipsisOffset;
}
return -1;
}
public override VisualLineElement ConstructElement(int offset)
{
return new FormattedTextElement(ellipsis, CurrentContext.VisualLine.LastDocumentLine.EndOffset - offset - charactersAfterEllipsis);
}
}
這段代碼的核心邏輯是:如果檢測到單行的字符串數量超過 2000 個(通過 maxLength 常量控制),那麼就省略中間部分的內容直接渲染為省略號(通過 ellipsis 常量控制)。此操作雖然會改變文字的顯示,但不會對全選複製造成影響。考慮到 JSON 在未縮進的情況下本身就不便於閱讀和編輯,所以使用該策略並不會對客戶造成影響。
JSON美化功能的超長文本自動截斷功能
應用該策略後,即便是超長的 JSON 也沒有造成性能問題(單行渲染的字符數被限制後,代碼着色也失效了)。美化縮進後的 JSON 很難觸發這個策略,且 AvalonEdit 在面對多行文本時效率表現優秀。
TruncateLongLines 的使用方法
使用以下代碼將 TruncateLongLines 添加到編輯器:
editor.TextArea.TextView.ElementGenerators.Add(new TruncateLongLines());
此外,為了獲得更好的性能你需要:
- 如果非必要,請禁用 textEditor.Options.EnableHyperlinks 和 EnableEmailHyperlinks 。
- 不要啟用 ShowSpaces 和 ShowTabs 。