Colorea diferentes partes de una cadena RichTextBox

109

Estoy tratando de colorear partes de una cadena para agregarlas a RichTextBox. Tengo una cuerda construida a partir de diferentes cuerdas.

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

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

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

Quiero que todo lo que esté dentro de los corchetes [9:23], incluido el mismo, sea de un color, que el "usuario" sea de otro color y que el mensaje sea de otro color. Entonces me gustaría que la cadena se agregara a mi RichTextBox.

¿Cómo puedo lograr esto?

Fatal510
fuente
5
Busqué y no encontré nada útil.
Fatal510
Gracias por esta sencilla solución, funciona bien para mí. No olvide usar AppendText (...) cada vez que desee agregar texto, y no usar el operador '+ =' o los colores aplicados se descartan.
Xhis

Respuestas:

238

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 un parpadeo si está enviando muchos mensajes. Consulte este artículo de C # Corner para obtener ideas sobre cómo reducir el parpadeo de RichTextBox.

Nathan Baulch
fuente
3
Tuve algunos problemas con esto. Usé en otro lugar box.Text += mystringy así desaparecieron todos los colores. Cuando reemplacé esto con box.AppendText(mystring), funcionó como un encanto.
Natrium
3
Tengo algunos problemas con el código, el color desaparece al agregar una cadena en algún otro color. La única diferencia es que estoy asignando un cuadro var a un cuadro de texto enriquecido previamente creado ...
manu_dilip_shah
¿Qué estoy haciendo mal ... "SelectionStart" no es una propiedad de un RichTextBox (o al menos no puedo acceder a él)? Encontré "Selección", pero es una propiedad de solo
obtención
2
Esto es específicamente para WinForms. ¿Estás usando WPF por casualidad?
Nathan Baulch
No tengo sobrecarga, ikee esto, solo AppendText(string text)con WinForms
vaso123
12

He expandido el método con 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.
fuente
Nota: para que esto funcione, debe utilizar el método AppendText. Asignar algo a la propiedad de texto del cuadro lo romperá.
Jeff
9

Esta es la versión modificada que puse en mi código (estoy usando .Net 4.5) pero creo que también debería funcionar 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
  • insertó ScrollToCaret para forzar el desplazamiento automático
  • se agregaron llamadas de suspensión / reanudación de diseño
tedebus
fuente
6

Creo que modificar un "texto seleccionado" en un RichTextBox no es la forma correcta de agregar texto en color. Así que aquí hay 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);

Desde 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

  • InlineUIContainer

  • correr

  • Lapso

  • Negrita

  • Hipervínculo

  • Itálico

  • Subrayar

  • LineBreak

Así que creo que tienes que dividir tu cadena según el color de las partes y crear tantos Runobjetos como necesites.

Elo
fuente
Esperaba que esta fuera la respuesta que realmente estaba buscando, pero parece ser una respuesta de WPF y no una respuesta de WinForms.
Kristen Hammack
3

¡Es un trabajo para mí! ¡Espero que te sea de utilidad!

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;
}
Mohammad Fathi MiMFa
fuente
0

Al seleccionar texto como lo dijo alguien, puede que la selección aparezca momentáneamente. En Windows Forms applicationsno hay otras soluciones para el problema, pero hoy he encontrado un mal, de trabajo, manera de resolver: se puede poner una PictureBoxen superposición a laRichtextBox con la captura de pantalla de si, durante la selección y el color o la fuente cambiante, por lo que es después de reaparecerán todos, cuando finalice la operación.

El código está aquí ...

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

Mejor es usar WPF; esta solución no es perfecta, pero para Winform funciona.


fuente
0
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;

        }
KhaledDev
fuente
0

Al usar Selection en WPF, agregando desde varias otras respuestas, no se requiere ningún otro código (excepto la enumeración de gravedad y la función 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();
    }
Honza Nav
fuente
0

Creé esta función después de investigar en Internet, ya que quería imprimir una cadena XML cuando selecciona una fila de una vista de cuadrícula de datos.

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

y así es como lo llamas

   HighlightPhrase(richTextBox1, "<", ">","</", Color.Red, Color.Black);
N.Tesla
fuente
Esto no resuelve el problema dado, solo ilustra cómo podría funcionar la solución.
Josef Bláha