Colorez différentes parties d'une chaîne RichTextBox

109

J'essaie de colorer les parties d'une chaîne à ajouter à un RichTextBox. J'ai une chaîne construite à partir de différentes chaînes.

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

Voici à quoi ressemblerait le message une fois construit.

[21:23] Utilisateur: mon message ici.

Je veux que tout ce qui se trouve entre et y compris les crochets [9:23] soit d'une seule couleur, «utilisateur» d'une autre couleur et le message d'une autre couleur. Ensuite, j'aimerais que la chaîne soit ajoutée à mon RichTextBox.

Comment puis-je accomplir cela?

Fatal510
la source
5
J'ai fait des recherches et je n'ai trouvé rien d'utile.
Fatal510
Merci pour cette solution simple, fonctionne très bien pour moi. N'oubliez pas d'utiliser le AppendText (...) chaque fois que vous souhaitez ajouter du texte, et n'utilisez pas l'opérateur '+ =' ou les couleurs appliquées sont ignorées.
Xhis

Réponses:

239

Voici une méthode d'extension qui surcharge la AppendTextméthode avec un paramètre de couleur:

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

Et voici comment vous l'utiliseriez:

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

Notez que vous remarquerez peut-être un scintillement si vous envoyez beaucoup de messages. Consultez cet article du coin C # pour des idées sur la façon de réduire le scintillement RichTextBox.

Nathan Baulch
la source
3
J'ai eu quelques problèmes avec ça. J'ai utilisé dans un autre endroit box.Text += mystringet donc toutes les couleurs ont disparu. Quand j'ai remplacé cela par box.AppendText(mystring), cela a fonctionné comme un charme.
Natrium
3
J'ai quelques problèmes avec le code, la couleur disparaît en ajoutant une chaîne dans une autre couleur.La seule différence est que j'attribue une boîte de var à une boîte de texte précédemment créée ....
manu_dilip_shah
Qu'est-ce que je fais de mal ... "SelectionStart" n'est pas une propriété d'un RichTextBox (ou je ne peux pas y accéder au moins)? J'ai trouvé "Selection" mais c'est une propriété
accessible
2
C'est spécifiquement pour WinForms. Utilisez-vous WPF par hasard?
Nathan Baulch
Je n'ai pas de surcharge comme ça, uniquement AppendText(string text)avec WinForms
vaso123 le
12

J'ai développé la méthode avec la police comme paramètre:

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.
la source
Remarque - pour que cela fonctionne, vous devez utiliser la méthode AppendText. Assigner quoi que ce soit à la propriété text de la boîte la cassera.
Jeff
9

C'est la version modifiée que j'ai mise dans mon code (j'utilise .Net 4.5) mais je pense que cela devrait aussi fonctionner sur 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();
}

Différences avec l'original:

  • possibilité d'ajouter du texte à une nouvelle ligne ou simplement l'ajouter
  • pas besoin de changer de sélection, ça marche de la même façon
  • inséré ScrollToCaret pour forcer le défilement automatique
  • ajout des appels de mise en page suspendre / reprendre
tedébus
la source
6

Je pense que modifier un "texte sélectionné" dans un RichTextBox n'est pas la bonne façon d'ajouter du texte coloré. Alors voici une méthode pour ajouter un "color block":

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

Depuis MSDN :

La propriété Blocks est la propriété de contenu de RichTextBox. C'est une collection d'éléments Paragraph. Le contenu de chaque élément Paragraph peut contenir les éléments suivants:

  • En ligne

  • InlineUIContainer

  • Courir

  • Envergure

  • Audacieux

  • Hyperlien

  • Italique

  • Souligner

  • Saut de ligne

Je pense donc que vous devez diviser votre chaîne en fonction de la couleur des pièces et créer autant d' Runobjets que nécessaire.

Elo
la source
J'espérais que c'était la réponse que je cherchais vraiment, mais cela semble être une réponse WPF et non une réponse WinForms.
Kristen Hammack
3

Ça marche pour moi! J'espère que cela vous sera 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;
}
Mohammad Fathi MiMFa
la source
0

En sélectionnant le texte comme dit de quelqu'un, la sélection peut apparaître momentanément. Il Windows Forms applicationsn'y a pas d'autres solutions au problème, mais aujourd'hui, j'ai trouvé une mauvaise façon de résoudre le problème: vous pouvez mettre un PictureBoxchevauchement dans leRichtextBox avec la capture d'écran de if, pendant la sélection et le changement de couleur ou de police, en le faisant après réapparaissent tous, lorsque l'opération est terminée.

Le code est là ...

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

Mieux vaut utiliser WPF; cette solution n'est pas parfaite, mais pour Winform cela fonctionne.


la source
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
la source
0

À l'aide de Selection dans WPF, en agrégeant à partir de plusieurs autres réponses, aucun autre code n'est requis (à l'exception de l'énumération Severity et de la fonction 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
la source
0

J'ai créé cette fonction après des recherches sur Internet car je voulais imprimer une chaîne XML lorsque vous sélectionnez une ligne dans une vue de grille de données.

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

et c'est comme ça que tu l'appelles

   HighlightPhrase(richTextBox1, "<", ">","</", Color.Red, Color.Black);
N.Tesla
la source
Cela ne résout pas le problème donné, illustre seulement comment la solution pourrait fonctionner.
Josef Bláha