Цвет различных частей строки RichTextBox
Я пытаюсь покрасить части строки, добавляемой в RichTextBox. У меня строка, построенная из разных строк.
string temp = "[" + DateTime.Now.ToShortTimeString() + "] " +
userid + " " + message + Environment.NewLine;
Это будет выглядеть сообщение после его создания.
[9:23 pm] Пользователь: мое сообщение здесь.
Я хочу, чтобы все внутри и в том числе скобки [9:23] были одним цветом, "пользователь" - другим цветом, а сообщение - другим цветом. Затем я хотел бы, чтобы строка была добавлена к моему RichTextBox.
Как я могу это сделать?
Ответы
Ответ 1
Вот метод расширения, который перегружает метод AppendText
с помощью параметра цвета:
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;
}
}
И вот как вы его используете:
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();
Обратите внимание, что вы можете заметить мерцание, если вы выводите много сообщений. См. этот С# Corner для идей о том, как уменьшить мерцание RichTextBox.
Ответ 2
Я расширил метод шрифтом как параметр:
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;
}
Ответ 3
Это модифицированная версия, которую я ввел в мой код (я использую .Net 4.5), но я думаю, что он тоже должен работать и с 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();
}
Различия с оригинальным:
- возможность добавить текст в новую строку или просто добавить его
- Не нужно менять выбор, он работает одинаково
- вставляется ScrollToCaret для принудительной автопрокрутки
- добавлены приглашения о приостановке/возобновлении макета
Ответ 4
Я думаю, что изменение "выделенного текста" в RichTextBox - это неправильный способ добавления цветного текста. Итак, вот способ добавления "цветного блока":
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);
Из MSDN:
Свойство Blocks - это свойство содержимого RichTextBox. Это сборник элементов абзаца. Содержимое каждого элемента абзаца может содержать следующие элементы:
-
В очереди
-
InlineUIContainer
-
Бег
-
пядь
-
Жирный
-
Гиперссылка
-
курсивный
-
подчеркивание
-
Разрыв строки
Поэтому я думаю, что вам нужно разделить свою строку в зависимости от цвета детали и создать столько объектов Run
сколько необходимо.
Ответ 5
Это работает для меня! Я надеюсь, что это будет полезно для вас!
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;
}
Ответ 6
Выбор текста, как сказал кто-то, может отобразиться кратковременно.
В Windows Forms applications
нет других решений проблемы, но сегодня я нашел плохой, рабочий и способ решить: вы можете поместить PictureBox
в наложение на RichtextBox
с снимком экрана, если во время выбора и меняя цвет или шрифт, создавая его после повторного появления всех, когда операция завершена.
Код здесь...
//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();
Лучше использовать WPF; это решение не идеально, но для Winform оно работает.
Ответ 7
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;
}
Ответ 8
Используя Selection в WPF, агрегируя из нескольких других ответов, никакой другой код не требуется (кроме перечисления Severity и функции 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();
}