Colorea diferentes partes de una cadena RichTextBox

Resuelto Fatal510 asked hace 14 años • 10 respuestas

Estoy intentando colorear partes de una cadena para agregarla a un RichTextBox. Tengo una cadena construida a partir de diferentes cadenas.

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

Así es como se vería el mensaje una vez construido.

[9:23pm] Usuario: mi mensaje aquí.

Quiero que todo lo que esté dentro de los corchetes [9:23] e incluidos sea de un color, 'usuario' sea de otro color y el mensaje sea de otro color. Entonces me gustaría agregar la cadena a mi RichTextBox.

¿Cómo puedo lograr esto?

Fatal510 avatar Dec 18 '09 11:12 Fatal510
Aceptado

Aquí hay un método de extensión que sobrecarga el AppendTextmétodo con un parámetro de color:

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

Y así es como lo usarías:

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

Tenga en cuenta que puede notar algo de parpadeo si envía muchos mensajes. Consulte este artículo de C# Corner para obtener ideas sobre cómo reducir el parpadeo de RichTextBox.

Nathan Baulch avatar Dec 18 '2009 07:12 Nathan Baulch

He ampliado el método con la fuente como parámetro:

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;
}
Renan F. avatar Sep 29 '2015 18:09 Renan F.

Esta es la versión modificada que puse en mi código (estoy usando .Net 4.5) pero creo que debería funcionar también en 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();
}

Diferencias con el original:

  • Posibilidad de agregar texto a una nueva línea o simplemente agregarlo
  • No es necesario cambiar la selección, funciona igual.
  • Insertado ScrollToCaretpara forzar el desplazamiento automático
  • Agregado SuspendLayout/ResumeLayout requiere un mejor rendimiento
tedebus avatar Feb 16 '2017 12:02 tedebus

EDITAR: lo siento, esta es una respuesta de WPF

Creo que modificar un "texto seleccionado" en RichTextBox no es la forma correcta de agregar texto en color. Aquí un método para agregar un "bloque de color":

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

De MSDN :

La propiedad Blocks es la propiedad de contenido de RichTextBox. Es una colección de elementos de párrafo. El contenido de cada elemento de Párrafo puede contener los siguientes elementos:

  • En línea

  • Contenedor UI en línea

  • Correr

  • Durar

  • Atrevido

  • Hipervínculo

  • Itálico

  • Subrayar

  • Salto de línea

Entonces creo que debes dividir la cadena según el color de las partes y crear tantos Runobjetos como sea necesario.

Elo avatar Mar 08 '2018 13:03 Elo

¡Es trabajo para mí! ¡Espero que te sea útil!

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;
}
MiMFa avatar Dec 09 '2018 13:12 MiMFa