Pokoloruj różne części ciągu RichTextBox

109

Próbuję pokolorować części ciągu, które mają zostać dołączone do RichTextBox. Mam ciąg zbudowany z różnych ciągów.

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

Tak wyglądałaby wiadomość po jej skonstruowaniu.

[21:23] Użytkownik: moja wiadomość tutaj.

Chcę, aby wszystko w nawiasach [9:23] i łącznie z nimi miało jeden kolor, „użytkownik” miał inny kolor, a komunikat - innym kolorem. Następnie chciałbym, aby ciąg został dołączony do mojego RichTextBox.

Jak mogę to osiągnąć?

Śmiertelny510
źródło
1
naiwniaczek? stackoverflow.com/questions/455713/…
abhilash
5
Wyszukałem i nie znalazłem żadnego z nich przydatnego.
Fatal510
Dzięki za to proste rozwiązanie, dla mnie działa dobrze. Nie zapomnij użyć AppendText (...) za każdym razem, gdy chcesz dołączyć tekst i nie używać operatora „+ =” lub zastosowane kolory są odrzucane.
Xhis

Odpowiedzi:

239

Oto metoda rozszerzenia, która przeciąża AppendTextmetodę parametrem koloru:

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

A tak byś tego użył:

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

Zwróć uwagę, że możesz zauważyć migotanie, jeśli wyświetlasz dużo wiadomości. Zobacz ten artykuł C # Corner, aby zapoznać się z pomysłami na zmniejszenie migotania RichTextBox.

Nathan Baulch
źródło
3
Miałem z tym jakiś problem. Użyłem w innym miejscu box.Text += mystringi wszystkie kolory zniknęły. Kiedy zastąpiłem to box.AppendText(mystring), działało jak urok.
Natrium
3
Mam problem z kodem, kolor znika po dodaniu napisu w innym kolorze. Jedyną różnicą jest to, że przypisuję pole var do wcześniej utworzonego
richtextbox
Co robię źle ... „SelectionStart” nie jest właściwością RichTextBox (lub przynajmniej nie mam do niego dostępu)? Znalazłem „Selection”, ale jest to właściwość tylko do pobrania ...
00jt
2
Dotyczy to szczególnie WinForms. Czy używasz WPF przez przypadek?
Nathan Baulch
Nie mam tego przeciążenia, tylko AppendText(string text)z WinForms
vaso123
12

Rozszerzyłem metodę o czcionkę jako parametr:

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.
źródło
Uwaga - aby to zadziałało musisz użyć metody AppendText. Przypisanie czegokolwiek do właściwości text pola spowoduje jego zerwanie.
Jeff
9

To jest zmodyfikowana wersja, którą umieściłem w swoim kodzie (używam .Net 4.5), ale myślę, że powinna też działać na 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();
}

Różnice w stosunku do oryginału:

  • możliwość dodania tekstu do nowej linii lub po prostu dopisania go
  • nie trzeba zmieniać wyboru, działa to samo
  • wstawiono ScrollToCaret, aby wymusić automatyczne przewijanie
  • dodano wywołania układu zawieszenia / wznowienia
tedebus
źródło
6

Myślę, że modyfikowanie „zaznaczonego tekstu” w RichTextBox nie jest właściwym sposobem dodawania kolorowego tekstu. Oto metoda dodawania „bloku koloru”:

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

Z MSDN :

Właściwość Blocks jest właściwością Content RichTextBox. Jest to zbiór elementów akapitu. Zawartość każdego elementu akapitu może zawierać następujące elementy:

  • Inline

  • InlineUIContainer

  • Biegać

  • Zakres

  • Pogrubienie

  • Hiperłącze

  • italski

  • Podkreślać

  • Przerwanie linii

Więc myślę, że musisz podzielić swój ciąg w zależności od koloru części i stworzyć tyle Runobiektów, ile potrzeba.

Elo
źródło
Miałem nadzieję, że to jest odpowiedź, której naprawdę szukałem, ale wydaje się, że jest to odpowiedź WPF, a nie odpowiedź WinForms.
Kristen Hammack
3

Na mnie to działa! Mam nadzieję, że Ci się przyda!

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
źródło
0

Wybierając tekst tak, jak ktoś powiedział, może to na chwilę pojawić się. W Windows Forms applicationsnie ma innych rozwiązań dla problemu, ale dziś znalazłam zły, pracy, sposób rozwiązania: można umieścić PictureBoxw nakładających się doRichtextBox na zrzut ekranu z if, podczas selekcji i zmiany koloru lub czcionki, robiąc to po pojawią się ponownie po zakończeniu operacji.

Kod jest tutaj ...

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

Lepiej jest użyć WPF; to rozwiązanie nie jest idealne, ale dla Winform działa.


źródło
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
źródło
0

Korzystanie z Selection w WPF, agregowanie z kilku innych odpowiedzi, żaden inny kod nie jest wymagany (z wyjątkiem wyliczenia Severity i funkcji 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
źródło
0

Utworzyłem tę funkcję po wyszukaniu informacji w Internecie, ponieważ chciałem wydrukować ciąg XML po wybraniu wiersza z widoku siatki danych.

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

i tak to nazywasz

   HighlightPhrase(richTextBox1, "<", ">","</", Color.Red, Color.Black);
N.Tesla
źródło
To nie rozwiązuje danego problemu, a jedynie ilustruje, jak rozwiązanie może działać.
Josef Bláha