我目前正致力于语法突出显示和代码完成项目,并基于RichTextBox进行用户控制。我在适应RTB的工作方式和一切方面遇到了一些问题,但我设法做了简单的语法高亮。
简单意味着每次用户键入字符时都会突出显示整个文本。它不应该是快速或任何东西,但它太慢。当我有大约500个字符值的文本时性能问题变得可见,并且我只对每个类型字符传递一个文本('colorInterval'函数在一次传递中被调用大约100次)。
性能分析说问题是TextRange构造函数占用了大约80%以上的时间,而且每次我需要为文本间隔着色时都会使用它:
private void colorInterval(TextPointer start, TextPointer end)
{
TextRange range = new TextRange(start, end);
if(isFunction(range.Text)) colorAsFunction(range);
if(isInQuotes(range.Text)) colorAsQuoted(range);
...
}
所以这里有我的问题:
我做错了什么都是这样做的,还是有办法提高TextRange的性能,回收'范围'对象或类似的东西?还有哪些其他解决方案。
答案 0 :(得分:1)
最简单的方法是(按照你的建议)重用TextRange
对象,如果它真的是占用大部分时间的构造函数。 TextRange
属性Start
和End
是只读的,但有一个公共方法Select
将更新这两个,获取两个TextPointer
对象,就像构造函数一样你一直在使用。
protected TextRange range;
private void colorInterval(TextPointer start, TextPointer end)
{
if (range == null)
range = new TextRange(start, end);
else
range.Select(start, end);
...
}
(NB在确定是否初始化变量之前检查空引用并不像在声明中实例化TextRange
那样整洁。不幸的是,TextRange
没有公共空构造函数和{{ 1}}根本没有公共构造函数。你可以在类构造函数中创建一些虚拟值来避免这种检查。)
上面,我说'如果它真的是构造函数'。显然,你正确完成的分析突出了构造函数,但它可以很容易地成为构造函数和TextPointer
方法的常用例程。
假设你没有从多个线程中调用Select
,我会说这是一个比现在更好的方法,因为(我猜)colorInterval
是经常被调用,它留下的后续colorInterval
对象的不断创建和垃圾收集肯定是效率低下的。
提出这个建议之后,我强烈建议您在每次想要对单个字符更改做出反应时(例如)对每个扫描整个文档的模型进行移动。假设您的目标是> = .net 3.5,TextRange
提供RichTextBox
事件,该事件报告TextChanged
个对象的列表,您可以从中计算出的位置(以及添加的字符或删除)改变。
当然,这里会有一些工作,因为任何改变都不可能完全封装突出显示的范围。 TextChange
类有一个方法可以找到可以找到范围的开头和结尾的段落,如果有帮助的话。可能存在每个突出显示范围的详细信息,以便您可以快速检查交叉点。