简体   繁体   English

RichTextBox中TextRange构造函数的性能

[英]TextRange constructor performance in RichTextBox

I am currently working on syntax highlighting and code completion project, and making user control based on RichTextBox. 我目前正在从事语法突出显示和代码完成项目,并基于RichTextBox进行用户控制。 I've had some problems adapting to the way RTB works and everything, but I have managed to make simple syntax highlighting. 我在适应RTB的工作方式和所有问题时遇到了一些问题,但是我设法进行了简单的语法突出显示。

Simple means that I highlight entire text every time user types a character. 简单意味着每次用户键入字符时,我都会突出显示整个文本。 It's not supposed to be fast or anything, but it is too slow . 它不应该是快速的或任何东西,但是它太慢了 Performance issues become visible when I have about 500 chars worth of text, and I do only one pass through the text for each typed character('colorInterval' function gets called about 100 times in one pass). 当我有大约500个字符的文本时,就会出现性能问题,并且对于每个键入的字符,我只对文本进行一次遍历(“ colorInterval”函数在一次遍历中被调用了约100次)。

Performance analysis says the problem is TextRange constructor that takes about 80%+ of the time, and I use it every time I need to color an interval of text: 性能分析说,问题是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);
        ...
    }

So here goes my question : 所以这是我的问题

Am I doing something wrong doing everything this way, or is there a way to boost performance of TextRange, recycle the 'range' object or something like that? 我是否以这种方式做任何事情都是错误的,还是有办法提高TextRange的性能,回收“范围”对象或类似的东西? What other solutions are there. 还有什么其他解决方案。

The simplest avenue is to (as you suggest) reuse the TextRange object, if it really is the constructor that is taking up most of your time. 最简单的方法是(如您建议的那样)重用TextRange对象,如果它确实是占用大部分时间的构造函数。 The TextRange properties Start and End are read only, but there is a public method Select which will update both, taking two TextPointer objects just like the constructor you have been using. TextRange属性的StartEnd是只读的,但是有一个公共方法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 checking for a null reference before deciding whether to initialise the variable isn't as neat as just instantiating a TextRange in the declaration. Unfortunately, TextRange has no public empty constructor and TextPointer no public constructors at all. You could create it with some dummy values in your class constructor to avoid this check.) (注:在决定是否初始化变量之前检查空引用并不像在声明中实例化TextRange那样整洁。不幸的是, TextRange没有公共的空构造函数,而TextPointer没有公共的构造函数。您可以使用一些方法来创建它类构造函数中的虚拟值,以避免此检查。)

Above, I said 'if it really is the constructor'. 在上面,我说过“如果真的是构造函数”。 Obviously, the profiling you've rightfully done has highlighted the constructor, but it could just as easily be a routine common to the constructor and the Select method. 显然,您正确完成的概要分析突出了构造函数,但它很容易成为构造函数和Select方法的通用例程。

Assuming you don't call colorInterval from more than one thread, I would say this is a better approach than you have currently whatever the time saving, because (I would guess that) colorInterval is being called frequently and constant creation and garbage collection of the subsequent TextRange objects it leaves behind is certainly an inefficiency. 假设您不从多个线程中调用colorInterval ,那么我想说这是一种比您目前节省时间的方法更好的方法,因为(我猜想) colorInterval被频繁调用,并且常量的创建和垃圾回收它留下的后续TextRange对象肯定是效率低下的。

Having made this suggestion, I strongly suggest you move away from the model where you scan the entire document every time you want to react to (for example) a single character change. 提出此建议后,我强烈建议您离开要在每次要对(例如)单个字符更改做出反应时扫描整个文档的模型。 Assuming you are targetting >= .net 3.5, the RichTextBox provides a TextChanged event that reports a list of TextChange objects from which you can work out the location of (and characters added or removed by) changes. 假设您的目标是> = .net 3.5, RichTextBox提供一个TextChanged事件,该事件报告一个TextChange对象列表,您可以从中确定更改的位置(以及更改所添加或删除的字符)。

Naturally, there will be some work here because any change is unlikely to completely encapsulate a highlighted range. 当然,这里会有一些工作,因为任何更改都不太可能完全封装突出显示的范围。 The TextRange class has a method for finding the paragraphs in which the start and end of a range can be found, in case that helps. TextRange类具有一种查找段落的方法,如果有帮助,可以在其中找到范围的开始和结束。 There's probably a case for storing details of each highlighted range so you can quickly check for intersection. 可能需要存储每个突出显示范围的详细信息,以便您可以快速检查交叉点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM