Colora parti diverse di una stringa RichTextBox


109

Sto cercando di colorare parti di una stringa da aggiungere a un RichTextBox. Ho una stringa composta da stringhe diverse.

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

Questo è l'aspetto che avrà il messaggio una volta costruito.

[21:23] Utente: il mio messaggio qui.

Voglio che tutto ciò che è compreso tra parentesi [9:23] sia un colore, "utente" sia un altro colore e il messaggio sia un altro colore. Quindi vorrei che la stringa fosse aggiunta al mio RichTextBox.

Come posso farlo?



5
Ho cercato e non ho trovato nulla di utile.
Fatal510

Grazie per questa semplice soluzione, funziona bene per me. Non dimenticare di utilizzare AppendText (...) ogni volta che desideri aggiungere del testo e di non utilizzare l'operatore "+ =" altrimenti i colori applicati vengono scartati.
Xil

Risposte:


239

Ecco un metodo di estensione che sovraccarica il AppendTextmetodo con un parametro 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;
    }
}

Ed è così che lo useresti:

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

Tieni presente che potresti notare uno sfarfallio se stai emettendo molti messaggi. Vedi questo articolo di C # Corner per idee su come ridurre lo sfarfallio di RichTextBox.


3
Ho avuto qualche problema con questo. L'ho usato in un altro posto box.Text += mystringe così tutti i colori sono scomparsi. Quando l'ho sostituito con box.AppendText(mystring), ha funzionato alla grande.
Natrium

3
Ho qualche problema con il codice il colore scompare aggiungendo una stringa in un altro colore. L'unica differenza è che sto assegnando var box a un richtextbox creato in precedenza ....
manu_dilip_shah

Cosa sto sbagliando ... "SelectionStart" non è una proprietà di un RichTextBox (o almeno non posso accedervi)? Ho trovato "Selezione" ma è una proprietà solo per ottenere ...
00jt

2
Questo è specifico per WinForms. Stai usando WPF per caso?
Nathan Baulch

Non ho alcun sovraccarico come questo, solo AppendText(string text)con WinForms
vaso123

12

Ho ampliato il metodo con il carattere come parametro:

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

Nota: affinché funzioni è necessario utilizzare il metodo AppendText. Assegnare qualcosa alla proprietà text della casella la interromperà.
Jeff

9

Questa è la versione modificata che ho inserito nel mio codice (sto usando .Net 4.5) ma penso che dovrebbe funzionare anche su 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();
}

Differenze con l'originale:

  • possibilità di aggiungere del testo a una nuova riga o semplicemente di aggiungerlo
  • non è necessario modificare la selezione, funziona allo stesso modo
  • inserito ScrollToCaret per forzare lo scorrimento automatico
  • aggiunte le chiamate di sospensione / ripresa del layout

6

Penso che modificare un "testo selezionato" in un RichTextBox non sia il modo giusto per aggiungere testo colorato. Quindi ecco un metodo per aggiungere un "blocco di colore":

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

Da MSDN :

La proprietà Blocks è la proprietà del contenuto di RichTextBox. È una raccolta di elementi di paragrafo. Il contenuto in ogni elemento Paragraph può contenere i seguenti elementi:

  • In linea

  • InlineUIContainer

  • Correre

  • campata

  • Grassetto

  • collegamento ipertestuale

  • Corsivo

  • Sottolineare

  • Interruzione di linea

Quindi penso che devi dividere la stringa in base al colore delle parti e creare tutti gli Runoggetti necessari.


Speravo che questa fosse la risposta che stavo davvero cercando, ma sembra essere una risposta WPF e non una risposta WinForms.
Kristen Hammack

3

Per me funziona! Spero ti sia utile!

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

0

Selezionando il testo come detto da qualcuno, la selezione potrebbe apparire momentaneamente. Non Windows Forms applicationsci sono altre soluzioni per il problema, ma oggi ho trovato un modo mal funzionante per risolverlo: puoi mettere un PictureBoxin sovrapposizione al RichtextBoxcon lo screenshot di se, durante la selezione e il cambio di colore o carattere, rendendolo dopo ricompaiono tutti, ad operazione completata.

Il codice è qui ...

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

È meglio usare WPF; questa soluzione non è perfetta, ma per Winform funziona.


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;

        }

0

Utilizzando la selezione in WPF, aggregando da diverse altre risposte, non è richiesto altro codice (eccetto Severity enum e GetSeverityColor funzione)

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

0

Ho creato questa funzione dopo aver effettuato ricerche su Internet poiché volevo stampare una stringa XML quando si seleziona una riga da una visualizzazione griglia dati.

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

ed è così che lo chiami

   HighlightPhrase(richTextBox1, "<", ">","</", Color.Red, Color.Black);

Questo non risolve il problema dato, illustra solo come potrebbe funzionare la soluzione.
Josef Bláha
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.