C# 为 RichTextBox 字符串的不同部分着色

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1926264/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 21:55:00  来源:igfitidea点击:

Color different parts of a RichTextBox string

c#stringwinformscolorsrichtextbox

提问by Fatal510

I'm trying to color parts of a string to be appended to a RichTextBox. I have a string built from different strings.

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

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

This is what the message would look like once it is constructed.

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

[9:23pm] User: my message here.

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

I want everything within and including the brackets [9:23] to be one color, 'user' to be another color and the message to be another color. Then I'd like the string appended to my RichTextBox.

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

How can I accomplish this?

我怎样才能做到这一点?

采纳答案by Nathan Baulch

Here is an extension method that overloads the AppendTextmethod with a color parameter:

这是一个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;
    }
}

And this is how you would use it:

这就是你将如何使用它:

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();

Note that you may notice some flickering if you're outputting a lot of messages. See this C# Cornerarticle for ideas on how to reduce RichTextBox flicker.

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

回答by Renan F.

I have expanded the method with font as a parameter:

我已经用字体作为参数扩展了该方法:

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;
}

回答by Renan F.

Selecting text as said from somebody, may the selection appear momentarily. In Windows Forms applicationsthere is no other solutions for the problem, but today I found a bad, working, way to solve: you can put a PictureBoxin overlapping to the RichtextBoxwith the screenshot of if, during the selection and the changing color or font, making it after reappear all, when the operation is complete.

选择某人所说的文本,可能会立即显示该选择。在Windows Forms applications存在该问题没有其他解决办法,但今天我发现了一个错误,工作,方法来解决:你可以把PictureBox重叠的RichtextBox用,如果截图,在选择过程和不断变化的颜色或字体,使其后全部重新出现,当操作完成时。

Code is here...

代码在这里...

//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();

Better is to use WPF; this solution isn't perfect, but for Winform it works.

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

回答by tedebus

This is the modified version that I put in my code (I'm using .Net 4.5) but I think it should work on 4.0 too.

这是我放在代码中的修改版本(我使用的是 .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();
}

Differences with original one:

与原版的区别:

  • possibility to add text to a new line or simply append it
  • no need to change selection, it works the same
  • inserted ScrollToCaret to force autoscroll
  • added suspend/resume layout calls
  • 可以将文本添加到新行或简单地附加它
  • 无需更改选择,它的工作原理相同
  • 插入 ScrollToCaret 以强制自动滚动
  • 添加暂停/恢复布局调用

回答by KhaledDev

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;

        }

回答by Elo

I think modifying a "selected text" in a RichTextBox isn't the right way to add colored text. So here a method to add a "color block" :

我认为修改 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);

From MSDN:

MSDN

The Blocks property is the content property of RichTextBox. It is a collection of Paragraph elements. Content in each Paragraph element can contain the following elements:

  • Inline

  • InlineUIContainer

  • Run

  • Span

  • Bold

  • Hyperlink

  • Italic

  • Underline

  • LineBreak

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

  • 排队

  • 内联UI容器

  • 跨度

  • 胆大

  • 超链接

  • 斜体

  • 强调

  • 越线

So I think you have to split your string depending on parts color, and create as many Runobjects as needed.

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

回答by Honza Nav

Using Selection in WPF, aggregating from several other answers, no other code is required (except Severity enum and GetSeverityColor function)

在 WPF 中使用 Selection,从其他几个答案聚合,不需要其他代码(除了 Severity enum 和 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();
    }

回答by Mohammad Fathi MiMFa

It`s work for me! I hope it will be useful to you!

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

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;
}