【问题标题】:RichTextBox syntax highlightingRichTextBox 语法高亮
【发布时间】:2016-12-01 17:50:21
【问题描述】:

我正在与this code 合作。它用于在RichTextBox 中突出显示语法。我专门查看函数ProcessLine()OnTextChanged(),我已将其修改为:

protected override void OnTextChanged(EventArgs e)
{
    // Calculate stuff here.
    m_nContentLength = this.TextLength;

    int nCurrentSelectionStart = SelectionStart;
    int nCurrentSelectionLength = SelectionLength;

    m_bPaint = false;

    // Find the start of the current line.
    m_nLineStart = nCurrentSelectionStart;
    while ((m_nLineStart > 0) && (Text[m_nLineStart - 1] != '\n'))
        m_nLineStart--;
    // Find the end of the current line.
    m_nLineEnd = nCurrentSelectionStart;
    while ((m_nLineEnd < Text.Length) && (Text[m_nLineEnd] != '\n'))
        m_nLineEnd++;
    // Calculate the length of the line.
    m_nLineLength = m_nLineEnd - m_nLineStart;
    // Get the current line.
    m_strLine = Text.Substring(m_nLineStart, m_nLineLength);

    // Process this line.
    ProcessLine();

    m_bPaint = true;
}

// Process a line.
private void ProcessLine()
{
    // Save the position and make the whole line black
    int nPosition = SelectionStart;
    SelectionStart = m_nLineStart;
    SelectionLength = m_nLineLength;
    SelectionColor = Color.Black;

    /*// Process the keywords
    ProcessRegex(m_strKeywords, Settings.KeywordColor);
    // Process numbers
    if(Settings.EnableIntegers)
        ProcessRegex("\\b(?:[0-9]*\\.)?[0-9]+\\b", Settings.IntegerColor);
    // Process strings
    if(Settings.EnableStrings)
        ProcessRegex("\"[^\"\\\\\\r\\n]*(?:\\\\.[^\"\\\\\\r\\n]*)*\"", Settings.StringColor);
    // Process comments
    if(Settings.EnableComments && !string.IsNullOrEmpty(Settings.Comment))
        ProcessRegex(Settings.Comment + ".*$", Settings.CommentColor);*/

    SelectionStart = nPosition;
    SelectionLength = 0;
    SelectionColor = Color.Red;

    m_nCurSelection = nPosition;
}
  • 我的第一个问题是,当我在OnTextChanged() 中输入ProcessLine() 时,m_strLine 的末尾是否总是有一个换行符?最小值或m_strLine 会是“\n”和最大的“any#ofchars+\n”吗?

  • 所以我有这个权利,如果SelectionLength 为零,则SelectionStart 是我的插入符号位置,如果SelectionLength 大于零,我的插入符号位于SelectStart+SelectionLength

  • 我正在尝试修改此代码以为大量不同的语法表达式着色,并且我计划为每一行一次处理一个字符。粘贴或加载超过 20k 行的文件时,这如何公平?

【问题讨论】:

  • 这是一种非常基本的方法,不适用于较大的 sn-ps。它将非常缓慢,并且有很多闪烁和怪癖。与开箱即用的 RTF 控件相比,从更好的基础开始会更好!
  • 我最好尝试正则表达式每一行,就像他们在这里尝试做的那样?
  • 另外,只有在加载文件时,我才必须遍历每一行。另一方面,在编辑文件时,我一次只需要检查一行,但仍会重新绘制,但只有用户可以在 textarea 中看到的文本区域。这真的会像大家想象的那么慢吗?
  • 如果你想自己做 Costin Boldisor 在这里有一篇博文blogs.msdn.microsoft.com/cobold/2011/01/31/…

标签: c# richtextbox


【解决方案1】:

我现在只能建议您使用稳定、功能更强大且不易出错的东西,例如用于 .NET 的 Scintilla 和 Color Code。这些控件是免费和开源的。试试看:

ScintillaNET
ColorCode - Syntax Highlighting/Colorization for .NET

RichTextBox 在处理大文本时效率极低。即使你得到了一些不错的突出显示,性能问题也会很快开始出现。

【讨论】:

  • 一个很好的答案,但是......有没有办法用 RichTextBox 做到这一点?如果没有,您能否指导我创建自己的 TextBox 控件的正确方向?谢谢:)
【解决方案2】:

这将非常糟糕地扩展。如果您的目标只是一个正常运行的应用程序,您应该按照 DelegateX 的建议去做;如果你想学习如何做,首先要找出减少完成工作量的方法。为此,这里有一些一般性提示:

仅突出显示窗口内的文本将是一个没有任何视觉副作用的巨大改进 - 将文本分成块(按函数、方法、类等)并且仅突出显示可见也可能是可行的块,甚至被遮挡的部分,以避免偏移起始位置影响高光的问题。如果你不这样做,你会遇到这样的情况:第一个渲染的行在 if 或括号块的中间,结果你有一个不平衡的语法树。

您仍然无法使用 RichTextBox 控件处理 20k 行,但几千行应该很快。

【讨论】:

  • MVS 08 中没有可以处理 20k+ 行文本的内容吗?我只是不想从头开始创建这样的东西。可能只显示您所说的文本块,将其余部分保存在文本文件中,并在我需要时从文件中提取?
  • 我不知道有什么开箱即用的方法,不过——再一次——DelegateX 的任何一个建议都应该用最少的努力就能很好地完成。问题在于处理 20k 行文本本质上是复杂的:更改一行的长度会影响它之后的每一行。我相信 .NET 在幕后将整个块渲染为一个巨大的纹理 - 尽管我可能是错的 - 无论你做什么,它都会突突突突,这意味着你受到带宽的限制,而不是受到 CPU 的限制。跨度>
  • 在系统上最简单的方法是将每个文档分成 500 行左右的块,并根据需要将它们从内存中流式传输到磁盘。但是,这会使您的滚动条变得怪异,因此您需要处理它。修复滚动条将意味着扩展这些类以处理滚动不正确存在的空间。这就是为什么要找到一个处理大文件的文本编辑器如此困难的部分原因 - 这也是为什么大多数现代开发范例都涉及让您的代码分布在数十个或数百个单独文件中的部分原因。
【解决方案3】:

面对同样的问题,未能找到“5 分钟准备就绪”的解决方案,我开发了自己的 RichTextBox 扩展来突出显示 XML。

由于时间紧迫,我开发得很快,没有时间修改它 - 所以请随时完善它。

只需复制并粘贴扩展代码以与您的 RichTextBox 一起使用或复制整个 应用程序代码,包括同步和异步使用

扩展方法

// Use for asynchronous highlight
public delegate void VoidActionOnRichTextBox(RichTextBox richTextBox);

// Extension Class
public static class RichTextBoxExtensions
{
    public static void HighlightXml(this RichTextBox richTextBox)
    {
        new StandardHighlight().HighlightXml(richTextBox);
    }
    public async static void HighlightXmlAsync(this RichTextBox richTextBox)
    {
        var helper = new StandardHighlight();
        var win = new MainWindow();
        await Task.Factory.StartNew(() =>
        {
            richTextBox.Dispatcher.BeginInvoke(new VoidActionOnRichTextBox(helper.HighlightXml), richTextBox);
        });
    }        
}

// You can extent it with more highlight methods
public class StandardHighlight
{        
    public void HighlightXml(RichTextBox richTextBox)
    {
        // Collect Text-Box Information
        var textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd).Text;
        XDocument xDocument;
        try
        {
            xDocument = XDocument.Parse(textRange);
        }
        catch
        {
            return;
        }
        var documentLines = xDocument.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None);

        // Get the Longest Line Length
        int? maxVal = null;
        for (int i = 0; i < documentLines.Length; i++)
        {
            int thisNum = documentLines[i].Length;
            if (!maxVal.HasValue || thisNum > maxVal.Value) { maxVal = thisNum; }
        }

        // Set Text-Box Width & Clear the Current Content
        if (maxVal != null) richTextBox.Document.PageWidth = (double)maxVal * 5.5;
        richTextBox.Document.Blocks.Clear();

        #region *** Process Lines ***
        foreach (var documentLine in documentLines)
        {
            // Parse XML Node Components
            var indentSpace = Regex.Match(documentLine, @"\s+").Value;
            var xmlTags = Regex.Matches(documentLine, @"(<[^/].+?)(?=[\s])|(<[^/].+?>)|(</.+?>)");
            if (documentLine.Contains("<!--")) xmlTags = Regex.Matches(documentLine, @"(<[^/].+?>)"); // Parse comments
            var nodeAttributes = Regex.Matches(documentLine, @"(?<=\s)(.+?)(?=\s)");

            // Process XML Node
            var nodeAttributesCollection = new List<Run>();
            if (nodeAttributes.Count > 0)
            {
                for (int i = 0; i < nodeAttributes.Count; i++)
                {
                    if (!(nodeAttributes[i].Value.Length < 2) && !(documentLine.Contains("<!--")))
                    {
                        var attributeName = $"{Regex.Match(nodeAttributes[i].Value, @"(.+?=)").Value}";
                        if (i == 0) attributeName = $" {Regex.Match(nodeAttributes[i].Value, @"(.+?=)").Value}";
                        var attributeValue = $"{Regex.Match(nodeAttributes[i].Value, @"(?<=(.+?=))"".+?""").Value} ";

                        if (i == nodeAttributes.Count - 1) attributeValue = attributeValue.Trim();
                        nodeAttributesCollection.Add(new Run { Foreground = new SolidColorBrush(Colors.Green), Text = $"{attributeName}" });
                        nodeAttributesCollection.Add(new Run { Foreground = new SolidColorBrush(Colors.Brown), Text = $"{attributeValue}" });
                    }
                }
            }

            // Initialize IndentSpace
            Run run = null;
            if (indentSpace.Length > 1) run = new Run { Text = indentSpace };

            // Initialize Open Tag
            var tagText = xmlTags[0].Value.Substring(1, xmlTags[0].Value.Length - 2);
            var tagTextBrush = new SolidColorBrush(Colors.Blue);
            var tagBorderBruh = new SolidColorBrush(Colors.Red);
            if (tagText.StartsWith("!--"))
            {
                tagTextBrush = new SolidColorBrush(Colors.DarkSlateGray);
                tagBorderBruh = new SolidColorBrush(Colors.DarkSlateGray);
            }
            var openTag = new Run
            {
                Foreground = tagTextBrush,
                Text = tagText
            };

            // Initialize Content Tag
            var content = new Run
            {
                Foreground = new SolidColorBrush(Colors.Black),
            };

            // Initialize Paragraph
            var paragraph = new Paragraph();
            paragraph.Margin = new Thickness(0);
            if (run != null) paragraph.Inlines.Add(run); // Add indent space if exist

            // Process Open Tag
            paragraph.Inlines.Add(new Run { Foreground = tagBorderBruh, Text = "<" });
            paragraph.Inlines.Add(openTag);

            // Process Open Tag Attributes
            if (nodeAttributesCollection.Count > 0)
            {
                nodeAttributesCollection.ForEach(attribute => { paragraph.Inlines.Add(attribute); });
                nodeAttributesCollection.Clear();
            }
            paragraph.Inlines.Add(new Run { Foreground = tagBorderBruh, Text = ">" });

            // Process Closing Tag
            if (xmlTags.Count > 1)
            {
                Run closingTag = new Run();
                content.Text = documentLine.Replace(xmlTags[0].Value, "").Replace(xmlTags[1].Value, "").Trim();
                closingTag = new Run
                {
                    Foreground = new SolidColorBrush(Colors.Blue),
                    Text = xmlTags[1].Value.Substring(1, xmlTags[1].Value.Length - 2)
                };
                paragraph.Inlines.Add(content);

                paragraph.Inlines.Add(new Run { Foreground = new SolidColorBrush(Colors.Red), Text = "<" });
                paragraph.Inlines.Add(closingTag);
                paragraph.Inlines.Add(new Run { Foreground = new SolidColorBrush(Colors.Red), Text = ">" });
            }
            richTextBox.Document.Blocks.Add(paragraph);
        }
        #endregion
    }
}

【讨论】:

    【解决方案4】:

    固定版本 - 将 JSON 处理为内部文本和更好的元素提取

            public static void HighlightXml(this RichTextBox richTextBox)
            {
                // Collect Text-Box Information
                var textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd).Text;
                XmlDocument xmlDocument = new XmlDocument();
                try
                {
                    xmlDocument.LoadXml(textRange.Trim());
                }
                catch
                {
                    return;
                }
                var documentLines = xmlDocument.OuterXml.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
    
                // Get the Longest Line Length
                int? maxVal = null;
                for (int i = 0; i < documentLines.Length; i++)
                {
                    int thisNum = documentLines[i].Length;
                    if (!maxVal.HasValue || thisNum > maxVal.Value) { maxVal = thisNum; }
                }
    
                // Set Text-Box Width & Clear the Current Content
                if (maxVal != null) richTextBox.Document.PageWidth = (double)maxVal * 10;
                richTextBox.Document.Blocks.Clear();
    
                #region *** Process Lines ***
                foreach (var documentLine in documentLines)
                {
                    // Parse XML Node Components
                    var indentSpace = Regex.Match(documentLine, @"\s+").Value;
                    var xmlTags = Regex.Matches(documentLine, @"(?<=<)[^>\s+]*");
                    if (documentLine.Contains("<!--")) xmlTags = Regex.Matches(documentLine, @"(<[^/].+?>)");
                    var nodeAttributes = Regex.Matches(documentLine, @"(?<=\s)[^><:\s]*=*(?=[>,\s])");
    
                    // Process XML Node
                    var nodeAttributesCollection = new List<Run>();
                    if (nodeAttributes.Count > 0)
                    {
                        for (int i = 0; i < nodeAttributes.Count; i++)
                        {
                            if (!(nodeAttributes[i].Value.Length < 2) && !(documentLine.Contains("<!--")))
                            {
                                var attributeName = $"{Regex.Match(nodeAttributes[i].Value, @"(.+?=)").Value}";
                                if (i == 0) attributeName = $" {Regex.Match(nodeAttributes[i].Value, @"(.+?=)").Value}";
                                var attributeValue = $"{Regex.Match(nodeAttributes[i].Value, @"(?<=(.+?=))"".+?""").Value} ";
    
                                if (i == nodeAttributes.Count - 1) attributeValue = attributeValue.Trim();
                                nodeAttributesCollection.Add(new Run { Foreground = new SolidColorBrush(Colors.Green), Text = $"{attributeName}" });
                                nodeAttributesCollection.Add(new Run { Foreground = new SolidColorBrush(Colors.Brown), Text = $"{attributeValue}" });
                            }
                        }
                    }
    
                    // Initialize IndentSpace
                    Run run = null;
                    if (indentSpace.Length > 1) run = new Run { Text = indentSpace };
    
                    // Initialize Open Tag
                    var tagText = xmlTags[0].Value;//.Substring(1, xmlTags[0].Value.Length - 2);
                    var tagTextBrush = new SolidColorBrush(Colors.Blue);
                    var tagBorderBruh = new SolidColorBrush(Colors.Red);
                    if (tagText.StartsWith("!--"))
                    {
                        tagTextBrush = new SolidColorBrush(Colors.DarkSlateGray);
                        tagBorderBruh = new SolidColorBrush(Colors.DarkSlateGray);
                    }
                    var openTag = new Run
                    {
                        Foreground = tagTextBrush,
                        Text = tagText
                    };
    
                    // Initialize Content Tag
                    var content = new Run
                    {
                        Foreground = new SolidColorBrush(Colors.Black),
                    };
    
                    // Initialize Paragraph
                    var paragraph = new Paragraph();
                    paragraph.Margin = new Thickness(0);
                    if (run != null) paragraph.Inlines.Add(run); // Add indent space if exist
    
                    // Process Open Tag
                    paragraph.Inlines.Add(new Run { Foreground = tagBorderBruh, Text = "<" });
                    paragraph.Inlines.Add(openTag);
    
                    // Process Open Tag Attributes
                    if (nodeAttributesCollection.Count > 0)
                    {
                        nodeAttributesCollection.ForEach(attribute => { paragraph.Inlines.Add(attribute); });
                        nodeAttributesCollection.Clear();
                    }
                    paragraph.Inlines.Add(new Run { Foreground = tagBorderBruh, Text = ">" });
    
                    // Process Closing Tag
                    if (xmlTags.Count > 1)
                    {
                        Run closingTag = new Run();
                        content.Text = documentLine.Replace($"<{xmlTags[0].Value}>", "").Replace($"<{xmlTags[1].Value}>", "").Trim();
                        closingTag = new Run
                        {
                            Foreground = new SolidColorBrush(Colors.Blue),
                            Text = xmlTags[1].Value.Substring(1, xmlTags[1].Value.Length - 1)
                        };
                        paragraph.Inlines.Add(content);
    
                        paragraph.Inlines.Add(new Run { Foreground = new SolidColorBrush(Colors.Red), Text = "<" });
                        paragraph.Inlines.Add(closingTag);
                        paragraph.Inlines.Add(new Run { Foreground = new SolidColorBrush(Colors.Red), Text = ">" });
                    }
                    richTextBox.Document.Blocks.Add(paragraph);
                }
                #endregion
            }
    

    【讨论】:

      猜你喜欢
      • 2013-08-13
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2011-08-24
      • 1970-01-01
      • 2015-11-12
      • 1970-01-01
      相关资源
      最近更新 更多