Color diferentes partes de una cadena RichTextBox

Intento colorear partes de una cadena para adjuntarlas 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 que se haya construido.

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

Quiero que todo dentro y que incluya los corchetes [9:23] sean de un color, ‘usuario’ sea de otro color y el mensaje sea de otro color. Entonces me gustaría que la cadena se adjunte a mi RichTextBox.

¿Cómo puedo lograr esto?

Aquí hay un método de extensión que sobrecarga el método AppendText 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 algunos parpadeos si está produciendo muchos mensajes. Consulte este artículo de C # Corner para obtener ideas sobre cómo reducir el parpadeo de RichTextBox.

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

Esta es la versión modificada que puse en mi código (estoy usando .Net 4.5) pero creo que debería funcionar en 4.0 también.

 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 anexarlo
  • no es necesario cambiar la selección, funciona igual
  • insertó ScrollToCaret para forzar el desplazamiento automático
  • Se agregaron llamadas al diseño suspender / reanudar

Seleccionando texto como dicho por alguien, puede que la selección aparezca momentáneamente. En Windows Forms applications no hay otras soluciones para el problema, pero hoy encontré una forma incorrecta de resolverlo: puede colocar un PictureBox superpuesto al RichtextBox con la captura de pantalla de si, durante la selección y el cambio de color o fuente, haciéndolo después de reaparecer todo, cuando la operación está completa.

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.

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

Creo que modificar un “texto seleccionado” en un RichTextBox no es la forma correcta de agregar texto de color. Entonces 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); 

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

  • Hiperenlace

  • Itálico

  • Subrayar

  • LineBreak

Por lo tanto, creo que debe dividir la cadena según el color de las partes y crear tantos objetos Run como sea necesario.