I\'m trying to color parts of a string to be appended to a RichTextBox. I have a string built from different strings.
string temp = \"[\" + DateTime.Now.ToSh
Here is an extension method that overloads the AppendText
method with a color parameter:
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;
}
}
And this is how you would use it:
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();
Note that you may notice some flickering if you're outputting a lot of messages. See this C# Corner article for ideas on how to reduce RichTextBox flicker.
Selecting text as said from somebody, may the selection appear momentarily.
In Windows Forms applications
there is no other solutions for the problem, but today I found a bad, working, way to solve: you can put a PictureBox
in overlapping to the RichtextBox
with the screenshot of if, during the selection and the changing color or font, making it after reappear all, when the operation is complete.
Code is here...
//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();
Better is to use WPF; this solution isn't perfect, but for Winform it works.
I have expanded the method with font as a parameter:
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;
}
I think modifying a "selected text" in a RichTextBox isn't the right way to add colored text. So here a method to add a "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);
From MSDN :
The Blocks property is the content property of RichTextBox. It is a collection of Paragraph elements. Content in each Paragraph element can contain the following elements:
Inline
InlineUIContainer
Run
Span
Bold
Hyperlink
Italic
Underline
LineBreak
So I think you have to split your string depending on parts color, and create as many Run
objects as needed.
I created this Function after researching on the internet since I wanted to print an XML string when you select a row from a data grid view.
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;
}
and this is how you call it
HighlightPhrase(richTextBox1, "<", ">","</", Color.Red, Color.Black);
It`s work for me! I hope it will be useful to you!
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;
}