【问题标题】:Color different parts of a RichTextBox string为 RichTextBox 字符串的不同部分着色
【发布时间】:2010-12-27 22:19:14
【问题描述】:

我正在尝试为要附加到 RichTextBox 的字符串部分着色。我有一个由不同字符串构建的字符串。

string temp = "[" + DateTime.Now.ToShortTimeString() + "] " +
              userid + " " + message + Environment.NewLine;

这就是消息构建后的样子。

[9:23pm] 用户:我的信息在这里。

我希望方括号 [9:23] 内的所有内容都为一种颜色,“用户”为另一种颜色,消息为另一种颜色。然后我想将字符串附加到我的 RichTextBox。

我怎样才能做到这一点?

【问题讨论】:

  • 我进行了搜索,但发现没有任何用处。
  • 感谢这个简单的解决方案,对我来说很好用。每次要附加文本时不要忘记使用 AppendText(...),不要使用 '+=' 运算符,否则应用的颜色会被丢弃。

标签: c# string winforms colors richtextbox


【解决方案1】:

我为 RichTextBox 控件准备了一个小助手,它可以很容易地在屏幕上生成彩色文本:

using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace Common.Helpers
{
    public class ColouredText
    {
        public string Text;
        public Color Foreground;
        public Color Background;

        public ColouredText(string text, Color foreground, Color background)
        {
            Text = text;
            Foreground = foreground;
            Background = background;
        }

        public ColouredText(string text, Color foreground) : this(text, foreground, Color.Transparent) { }

        public ColouredText(string text) : this(text, Color.Transparent, Color.Transparent) { }
    }

    public static class RichTextBoxHelper
    {
        private static RichTextBox _AppendText(RichTextBox box, string text, Color foreColor, Color backColor)
        {
            if (string.IsNullOrEmpty(text)) return box;

            box.SelectionStart = box.TextLength;
            box.SelectionLength = 0;

            box.SelectionColor = foreColor;
            box.SelectionBackColor = backColor;
            box.AppendText(text);
            box.SelectionColor = box.ForeColor;

            return box;
        }

        private static void _UpdateText(RichTextBox box, IEnumerable<ColouredText> newTextWithColors)
        {
            box.Text = "";

            foreach (var text in newTextWithColors)
            {
                var foreColor = text.Foreground; if (foreColor == Color.Transparent) foreColor = box.ForeColor;
                var backColor = text.Background; if (backColor == Color.Transparent) backColor = box.BackColor;

                _AppendText(box, text.Text, foreColor, backColor);
            }
        }

        public static void UpdateText(this RichTextBox richTextbox, IEnumerable<ColouredText> text)
        {
            if (richTextbox.InvokeRequired) richTextbox.Invoke((MethodInvoker)(() => { _UpdateText(richTextbox, text); }));
            else _UpdateText(richTextbox, text);
        }

        public static void UpdateText(this RichTextBox richTextbox, ColouredText text)
        {
            var list = new List<ColouredText>() { text };

            if (richTextbox.InvokeRequired) richTextbox.Invoke((MethodInvoker)(() => { _UpdateText(richTextbox, list); }));
            else _UpdateText(richTextbox, list);
        }
    }
}

现在你可以使用了:

var text = new List<ColouredText>()
{
    new ColouredText($"text#1    ", Color.Black),
    new ColouredText($"text#2    ", Color.Red, Color.Yellow),
    new ColouredText($" "),
    new ColouredText($"text#2    ", Color.White, Color.Black)
};

richTextBox1.UpdateText(text);

或更简单的单行文本用法:

richTextBox1.UpdateText(new ColouredText($"warning message", Color.Yellow, Color.Red));

【讨论】:

    【解决方案2】:

    编辑:抱歉,这是一个 WPF 答案

    我认为在 RichTextBox 中修改“选定文本”并不是添加彩色文本的正确方法。 所以这里有一个添加“色块”的方法:

            Run run = new Run("This is my text");
            run.Foreground = new SolidColorBrush(Colors.Red); // My Color
            Paragraph paragraph = new Paragraph(run);
            MyRichTextBlock.Document.Blocks.Add(paragraph);
    

    来自MSDN

    Blocks 属性是 RichTextBox 的内容属性。它是一个 段落元素的集合。每个段落元素中的内容 可以包含以下元素:

    • 内联

    • InlineUIContainer

    • 运行

    • 跨度

    • 粗体

    • 超链接

    • 斜体

    • 下划线

    • 换行

    所以我认为您必须根据零件颜色拆分字符串,并根据需要创建尽可能多的 Run 对象。

    【讨论】:

    • 我希望这是我真正想要的答案,但它似乎是 WPF 答案而不是 WinForms 答案。
    【解决方案3】:

    我在互联网上研究后创建了这个函数,因为我想在您从数据网格视图中选择一行时打印一个 XML 字符串。

    static void HighlightPhrase(RichTextBox box, string StartTag, string EndTag, string ControlTag, Color color1, Color color2)
    {
        int pos = box.SelectionStart;
        string s = box.Text;
        for (int ix = 0; ; )
        {
            int jx = s.IndexOf(StartTag, ix, StringComparison.CurrentCultureIgnoreCase);
            if (jx < 0) break;
            int ex = s.IndexOf(EndTag, ix, StringComparison.CurrentCultureIgnoreCase);
            box.SelectionStart = jx;
            box.SelectionLength = ex - jx + 1;
            box.SelectionColor = color1;
            
            int bx = s.IndexOf(ControlTag, ix, StringComparison.CurrentCultureIgnoreCase);
            int bxtest = s.IndexOf(StartTag, (ex + 1), StringComparison.CurrentCultureIgnoreCase);
            if (bx == bxtest)
            {
                box.SelectionStart = ex + 1;
                box.SelectionLength = bx - ex + 1;
                box.SelectionColor = color2;
            }
            
            ix = ex + 1;
        }
        box.SelectionStart = pos;
        box.SelectionLength = 0;
    }
    

    这就是你的称呼

       HighlightPhrase(richTextBox1, "<", ">","</", Color.Red, Color.Black);
    

    【讨论】:

    • 这并不能解决给定的问题,只是说明解决方案可能如何工作。
    【解决方案4】:

    这对我有用!希望对你有用!

    public static RichTextBox RichTextBoxChangeWordColor(ref RichTextBox rtb, string startWord, string endWord, Color color)
    {
        rtb.SuspendLayout();
        Point scroll = rtb.AutoScrollOffset;
        int slct = rtb.SelectionIndent;
        int ss = rtb.SelectionStart;
        List<Point> ls = GetAllWordsIndecesBetween(rtb.Text, startWord, endWord, true);
        foreach (var item in ls)
        {
            rtb.SelectionStart = item.X;
            rtb.SelectionLength = item.Y - item.X;
            rtb.SelectionColor = color;
        }
        rtb.SelectionStart = ss;
        rtb.SelectionIndent = slct;
        rtb.AutoScrollOffset = scroll;
        rtb.ResumeLayout(true);
        return rtb;
    }
    
    public static List<Point> GetAllWordsIndecesBetween(string intoText, string fromThis, string toThis,bool withSigns = true)
    {
        List<Point> result = new List<Point>();
        Stack<int> stack = new Stack<int>();
        bool start = false;
        for (int i = 0; i < intoText.Length; i++)
        {
            string ssubstr = intoText.Substring(i);
            if (ssubstr.StartsWith(fromThis) && ((fromThis == toThis && !start) || !ssubstr.StartsWith(toThis)))
            {
                if (!withSigns) i += fromThis.Length;
                start = true;
                stack.Push(i);
            }
            else if (ssubstr.StartsWith(toThis) )
            {
                if (withSigns) i += toThis.Length;
                start = false;
                if (stack.Count > 0)
                {
                    int startindex = stack.Pop();
                    result.Add(new Point(startindex,i));
                }
            }
        }
        return result;
    }
    

    【讨论】:

      【解决方案5】:

      在 WPF 中使用 Selection,从其他几个答案中聚合,不需要其他代码(除了 Severity 枚举和 GetSeverityColor 函数)

       public void Log(string msg, Severity severity = Severity.Info)
          {
              string ts = "[" + DateTime.Now.ToString("HH:mm:ss") + "] ";
              string msg2 = ts + msg + "\n";
              richTextBox.AppendText(msg2);
      
              if (severity > Severity.Info)
              {
                  int nlcount = msg2.ToCharArray().Count(a => a == '\n');
                  int len = msg2.Length + 3 * (nlcount)+2; //newlines are longer, this formula works fine
                  TextPointer myTextPointer1 = richTextBox.Document.ContentEnd.GetPositionAtOffset(-len);
                  TextPointer myTextPointer2 = richTextBox.Document.ContentEnd.GetPositionAtOffset(-1);
      
                  richTextBox.Selection.Select(myTextPointer1,myTextPointer2);
                  SolidColorBrush scb = new SolidColorBrush(GetSeverityColor(severity));
                  richTextBox.Selection.ApplyPropertyValue(TextElement.BackgroundProperty, scb);
      
              }
      
              richTextBox.ScrollToEnd();
          }
      

      【讨论】:

        【解决方案6】:
        private void Log(string s , Color? c = null)
                {
                    richTextBox.SelectionStart = richTextBox.TextLength;
                    richTextBox.SelectionLength = 0;
                    richTextBox.SelectionColor = c ?? Color.Black;
                    richTextBox.AppendText((richTextBox.Lines.Count() == 0 ? "" : Environment.NewLine) + DateTime.Now + "\t" + s);
                    richTextBox.SelectionColor = Color.Black;
        
                }
        

        【讨论】:

          【解决方案7】:

          这是我在代码中添加的修改版本(我使用的是 .Net 4.5),但我认为它也应该适用于 4.0。

          public void AppendText(string text, Color color, bool addNewLine = false)
          {
                  box.SuspendLayout();
                  box.SelectionColor = color;
                  box.AppendText(addNewLine
                      ? $"{text}{Environment.NewLine}"
                      : text);
                  box.ScrollToCaret();
                  box.ResumeLayout();
          }
          

          与原版的区别:

          • 可以将文本添加到新行或简单地追加它
          • 无需更改选择,效果相同
          • 插入 ScrollToCaret 以强制自动滚动
          • 添加了暂停/恢复布局调用

          【讨论】:

            【解决方案8】:

            选择某人所说的文本,可能会立即出现选择。 在Windows Forms applications 中没有其他解决方案,但今天我发现了一个不好的、有效的解决方法:您可以将PictureBoxRichtextBox 重叠,并在选择和改变颜色或字体,使其全部重新出现,当操作完成时。

            代码在这里...

            //The PictureBox has to be invisible before this, at creation
            //tb variable is your RichTextBox
            //inputPreview variable is your PictureBox
            using (Graphics g = inputPreview.CreateGraphics())
            {
                Point loc = tb.PointToScreen(new Point(0, 0));
                g.CopyFromScreen(loc, loc, tb.Size);
                Point pt = tb.GetPositionFromCharIndex(tb.TextLength);
                g.FillRectangle(new SolidBrush(Color.Red), new Rectangle(pt.X, 0, 100, tb.Height));
            }
            inputPreview.Invalidate();
            inputPreview.Show();
            //Your code here (example: tb.Select(...); tb.SelectionColor = ...;)
            inputPreview.Hide();
            

            更好的是使用WPF;这个解决方案并不完美,但对于 Winform 来说是可行的。

            【讨论】:

              【解决方案9】:

              我已经扩展了以字体为参数的方法:

              public static void AppendText(this RichTextBox box, string text, Color color, Font font)
              {
                  box.SelectionStart = box.TextLength;
                  box.SelectionLength = 0;
              
                  box.SelectionColor = color;
                  box.SelectionFont = font;
                  box.AppendText(text);
                  box.SelectionColor = box.ForeColor;
              }
              

              【讨论】:

              • 注意——要使这个工作你必须使用 AppendText 方法。将任何内容分配给框的 text 属性都会破坏它。
              【解决方案10】:

              这是一个扩展方法,它使用颜色参数重载AppendText 方法:

              public static class RichTextBoxExtensions
              {
                  public static void AppendText(this RichTextBox box, string text, Color color)
                  {
                      box.SelectionStart = box.TextLength;
                      box.SelectionLength = 0;
              
                      box.SelectionColor = color;
                      box.AppendText(text);
                      box.SelectionColor = box.ForeColor;
                  }
              }
              

              这就是你将如何使用它:

              var userid = "USER0001";
              var message = "Access denied";
              var box = new RichTextBox
                            {
                                Dock = DockStyle.Fill,
                                Font = new Font("Courier New", 10)
                            };
              
              box.AppendText("[" + DateTime.Now.ToShortTimeString() + "]", Color.Red);
              box.AppendText(" ");
              box.AppendText(userid, Color.Green);
              box.AppendText(": ");
              box.AppendText(message, Color.Blue);
              box.AppendText(Environment.NewLine);
              
              new Form {Controls = {box}}.ShowDialog();
              

              请注意,如果您输出大量消息,您可能会注意到一些闪烁。有关如何减少 RichTextBox 闪烁的想法,请参阅 this C# Corner 文章。

              【讨论】:

              • 我遇到了一些麻烦。我在另一个地方使用了box.Text += mystring,所以所有的颜色都消失了。当我用box.AppendText(mystring) 替换它时,它就像一个魅力。
              • 我在添加其他颜色的字符串时颜色消失的代码有一些问题。唯一的区别是我将 var 框分配给以前制作的richtextbox ....
              • 我做错了什么...“SelectionStart”不是 RichTextBox 的属性(或者我至少无法访问它)?我找到了“选择”,但它是一个只能获取的属性...
              • 这是专门为 WinForms 设计的。您是否有机会使用 WPF?
              • @vaso123 你必须自己添加。(例如类文件内部
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-06-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-10-06
              • 1970-01-01
              相关资源
              最近更新 更多