Colorir diferentes partes de uma string RichTextBox

109

Estou tentando colorir partes de uma string para ser anexada a um RichTextBox. Eu tenho uma corda feita de cordas diferentes.

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

É assim que a mensagem ficaria depois de construída.

[21:23] Usuário: minha mensagem aqui.

Quero que tudo dentro e incluindo os colchetes [9:23] seja de uma cor, 'usuário' seja outra cor e a mensagem seja de outra cor. Então, gostaria que a string fosse acrescentada ao meu RichTextBox.

Como posso fazer isso?

Fatal510
fonte
5
Eu fiz uma pesquisa e não achei nada útil.
Fatal510
Obrigado por esta solução simples, funciona bem para mim. Não se esqueça de usar AppendText (...) toda vez que quiser acrescentar texto e não usar o operador '+ =' ou as cores aplicadas serão descartadas.
Xhis

Respostas:

239

Aqui está um método de extensão que sobrecarrega o AppendTextmétodo 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ê o 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();

Observe que você pode notar alguma oscilação se estiver enviando muitas mensagens. Consulte este artigo do canto C # para obter ideias sobre como reduzir a oscilação de RichTextBox.

Nathan Baulch
fonte
3
Eu tive alguns problemas com isso. Usei em outro lugar box.Text += mystringe assim todas as cores desapareceram. Quando substituí isso por box.AppendText(mystring), funcionou como um encanto.
Natrium
3
Eu tenho alguns problemas com o código que a cor desaparece ao adicionar string em alguma outra cor. A única diferença é que estou atribuindo var box a um richtextbox feito anteriormente ....
manu_dilip_shah
O que estou fazendo de errado ... "SelectionStart" não é uma propriedade de um RichTextBox (ou pelo menos não consigo acessá-lo)? Encontrei "Selection", mas é uma propriedade somente para
obtenção
2
Isso é especificamente para WinForms. Você está usando o WPF por acaso?
Nathan Baulch
Eu não tenho sobrecarga ikee isso, apenas AppendText(string text)com WinForms
vaso123
12

Eu expandi o método com fonte 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.
fonte
Observação - para que isso funcione, você deve usar o método AppendText. Atribuir qualquer coisa à propriedade text da caixa irá quebrá-la.
Jeff
9

Esta é a versão modificada que coloquei no meu código (estou usando .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
  • inseriu ScrollToCaret para forçar a rolagem automática
  • adicionou suspender / retomar chamadas de layout
tedebus
fonte
6

Acho que modificar um "texto selecionado" em um RichTextBox não é a maneira certa de adicionar texto colorido. Portanto, aqui está um método para adicionar um "bloco de cor":

        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 de RichTextBox. É uma coleção de elementos de parágrafo. O conteúdo de cada elemento de parágrafo 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 corda dependendo da cor das partes e criar quantos Runobjetos forem necessários.

Elo
fonte
Eu esperava que essa fosse a resposta que eu realmente estava procurando, mas parece ser uma resposta WPF e não uma resposta WinForms.
Kristen Hammack
3

É trabalho para mim! Espero que seja útil para você!

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
fonte
0

Selecionando o texto como dito por alguém, a seleção pode aparecer momentaneamente. Em Windows Forms applicationsnão há outras soluções para o problema, mas hoje eu encontrei um mau, trabalho, maneira de resolver: você pode colocar um PictureBoxem sobreposição com a RichtextBoxcom a imagem de que, durante a seleção ea cor ou fonte mudando, tornando-se depois reaparecerão todos, quando a operação for concluída.

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.


fonte
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
fonte
0

Usando Seleção em WPF, agregando de várias outras respostas, nenhum outro código é necessário (exceto Severity enum e função 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
fonte
0

Criei esta função após pesquisar na internet, pois queria imprimir uma string XML ao selecionar uma linha em uma exibição de grade de dados.

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

e é assim que você chama

   HighlightPhrase(richTextBox1, "<", ">","</", Color.Red, Color.Black);
N.Tesla
fonte
Isso não resolve o problema fornecido, apenas ilustra como a solução pode funcionar.
Josef Bláha