Cor diferentes partes de uma string RichTextBox

Estou tentando colorir partes de uma string para ser anexado a um RichTextBox. Eu tenho uma string construída a partir de diferentes seqüências de caracteres.

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

É assim que a mensagem ficaria assim que fosse construída.

[9:23 pm] Usuário: minha mensagem aqui.

Eu quero que tudo dentro e incluindo os colchetes [9:23] seja uma cor, ‘usuário’ seja outra cor e a mensagem seja outra cor. Então eu gostaria que a string anexada ao meu RichTextBox.

Como posso fazer isso?

Aqui está um método de extensão que sobrecarrega o método AppendText com um parâmetro de cor:

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

E é assim que você usaria:

 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 que você pode notar alguma oscilação se estiver enviando muitas mensagens. Veja este artigo C # Corner para idéias sobre como reduzir a cintilação RichTextBox.

Eu expandi o método com fonte como um 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 é a versão modificada que eu coloquei no meu código (estou usando o .net 4.5), mas acho que deve funcionar no 4.0 também.

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

Diferenças com o original:

  • possibilidade de adicionar texto a uma nova linha ou simplesmente anexá-lo
  • não há necessidade de alterar a seleção, funciona da mesma
  • inserido ScrollToCaret para forçar autoscroll
  • adicionado suspender / retomar as chamadas de layout

Selecionando o texto como dito de alguém, a seleção pode aparecer momentaneamente. Nos Windows Forms applications não há outras soluções para o problema, mas hoje encontrei uma maneira ruim e funcional de resolver: você pode colocar um PictureBox em sobreposição ao RichtextBox com a captura de canvas se, durante a seleção e a cor ou alteração de cor fonte, tornando depois de reaparecer tudo, quando a operação estiver completa.

O código está aqui …

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

Melhor é usar o WPF; esta solução não é perfeita, mas para o 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; } 

Eu acho que modificar um “texto selecionado” em um RichTextBox não é o caminho certo para adicionar texto colorido. Então, aqui um método para adicionar um “bloco de colors”:

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

Do MSDN :

A propriedade Blocks é a propriedade de conteúdo do RichTextBox. É uma coleção de elementos Paragraph. O conteúdo de cada elemento Paragraph pode conter os seguintes elementos:

  • Na linha

  • InlineUIContainer

  • Corre

  • Período

  • Negrito

  • Hiperlink

  • itálico

  • Sublinhado

  • LineBreak

Então eu acho que você tem que dividir sua string dependendo da cor das peças, e criar quantos objects Run forem necessários.