Strange WinForms RichTextBox formatting effect - c#

I'm trying to format a RichTextBox object with the following code:
public static void MessageString(RichTextBox textBox, MessageModel model)
{
//textBox.SelectionFont = new Font("Consolas", 8.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
var message = new StringBuilder();
// date
message.Append(DateTimeString(model.RequestTime));
message.Append(" - ");
int start = textBox.Text.Length;
int length = message.Length - 1;
textBox.Text = string.Concat(textBox.Text, message.ToString());
textBox.DeselectAll();
textBox.Select(start, length);
textBox.SelectionColor = Color.LightGray;
textBox.PerformLayout();
// reset
message = new StringBuilder();
// time and user
message.Append(UserString(model.User));
message.Append(" wrote:");
message.Append(Environment.NewLine);
start = textBox.Text.Length;
length = message.Length - 1;
textBox.Text = string.Concat(textBox.Text, message.ToString());
textBox.DeselectAll();
textBox.Select(start, length);
textBox.SelectionColor = Color.Gray;
// reset
message = new StringBuilder();
// body
message.Append(model.Text);
message.Append(Environment.NewLine);
message.Append(Environment.NewLine);
start = textBox.Text.Length;
length = message.Length - 1;
textBox.Text = string.Concat(textBox.Text, message.ToString());
textBox.DeselectAll();
textBox.Select(start, length);
textBox.SelectionColor = Color.DarkBlue;
}
The problem is now, that the all text is formated with LightGray and only the body part os DarkBlue. The time and user part is also LightGray.
If i run this as part of a iteration list with more then one MessageModel, the whole textbox will be LightGray and only the last body part DarkBlue.
Actually i could not see the problem (forest, trees , u know). Each part should only select itself and formating it.
Could anyone help me?

Try replacing these lines
textBox.Text = string.Concat(textBox.Text, message.ToString());
with
textBox.AppendText(message.ToString());

Related

Calculating richtextbox lines count asynchronously

I write a code that counts the number of lines and text length from richtextbox content. With small chunks of text it work perfect. But when there large chunks of text (more than 100k) when I press "Enter" or "Backspace" in richtextbox, response time becomes very slow. For example: https://i.imgur.com/QO2UrAw.gifv
My question. What a better way to run this code asynchronously?
Archive with the test project https://gofile.io/?c=LpF409
private void StatusPanelTextInfo()
{
int currentColumn = 0;
int currentLine = 0;
int linesCount = 0;
if (statusStrip1.Visible)
{
currentColumn = 1 + richTextBox1.SelectionStart - richTextBox1.GetFirstCharIndexOfCurrentLine();
RichTextBox rtb = new RichTextBox
{
WordWrap = false,
Text = richTextBox1.Text
};
currentLine = 1 + rtb.GetLineFromCharIndex(richTextBox1.SelectionStart);
linesCount = richTextBox1.Lines.Count();
if (linesCount == 0)
{
linesCount = 1;
}
}
toolStripStatusLabel1.Text = "Length: " + richTextBox1.TextLength;
toolStripStatusLabel2.Text = "Lines: " + linesCount;
toolStripStatusLabel3.Text = "Ln: " + currentLine;
toolStripStatusLabel4.Text = "Col: " + currentColumn;
}
I downloaded your code and I can not understand why do you create a new RichTextBox every time you call StatusPanelTextInfo method:
RichTextBox rtb = new RichTextBox
{
WordWrap = false,
Text = richTextBox1.Text
};
This is the reason you got such a lag in your program. Each time you change/select text, you create a new RichTextBox object and copy a large amount of text to its Text property. You should remove this code, and then it works fast enough. Just replace rtb in your calculation of currentLine with richTextBox1.
Next time please provide your code in your question instead of making people download it from outer link. Your whole form class was about 60 lines. With proper selection you could have given us all the info we needed using 20 lines.

Richtextbox prepend new text with color

I have used a richtextbox to display logs in my WinForms.
Language used is C#.
The software is used for inserting data of Bank Branches and after start of new Branch I want to display a text with new color.
I have seen the link Color different parts of a RichTextBox string and implemeted it successfully.
My problem is I want to prepend the new line instead of append. That is the new line will be displayed on top.
I am able to do this by changing the code to box.Text=DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss") + ": " + text + box.Text
But the color is changing for the entire text.
This is the procedure used for append
box.SelectionStart = box.TextLength;
box.SelectionLength = 0;
box.SelectionColor = color;
box.AppendText(DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss") + ": " + text);
box.SelectionColor = box.ForeColor;
This is what I have done:
box.Text=DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss") + ": " + text + box.text;
box.SelectionStart = 0;
box.SelectionLength = text.length;
box.SelectionColor = color;
But this is not working.
1) Never directly change the Text property of an already formatted RichtTextBox
2) To append use the RTB.AppendText function
3) To insert at any other position p, including the beginning use this:
rtb.SelectionStart = s; // set the cursor to the target position
rtb.Selection.Length = 0; // nothing selected, yet
rtb.SelectedText = yourNewText; // this inserts the new text
Now you can add the formatting you want:
rtb.SelectionStart = s; // now we prepare the new formatting..
rtb.SelectionLength = yourNewText.Length; //.. by selecting the text
rtb.SelectionColor = Color.Blue; // and/or whatever you want to do..
...
// Prepend, normal on first line, rest of lines gray italic
private void PrependToRichTextbox(RichTextBox rt, string msg)
{
rt.SelectionStart = 0;
rt.SelectionLength = 0;
rt.SelectedText = msg + Environment.NewLine;
int linecount = 0;
foreach (var line in rt.Lines)
{
rt.Select(rt.GetFirstCharIndexFromLine(linecount), line.Length);
rt.SelectionColor = linecount == 0 ? Color.Black : Color.Gray;
Font currentFont = rt.SelectionFont;
FontStyle newFontStyle;
newFontStyle = linecount == 0 ? FontStyle.Regular : FontStyle.Italic;
rt.SelectionFont = new Font(
currentFont.FontFamily,
currentFont.Size,
newFontStyle
);
linecount++;
}
}

Formatting text using word.interop in outlook 2013 add-in

i'm trying to format text that i'm inserting at the beginning of a new email when a user presses a button in the ribbon add-in
the code is simple in that it first checks if the type of text was previously inserted, removes it if it was, and then inserts a new bracket of text using Word.Range.InsertBefore(.....);
the text will be:
CLASSIFICATION: .......
CLASSIFICATION: .......
the problem that i am running into is after the insert i'm formatting the font using Range.Font,Text etc...
i need the CLASSIFICATION: ...... formatted and not the space between them
the space between the "CLASSIFICATION......" is being formatted when typing begins to the same size, color, etc.... as the "CLASSIFICATION"
the code i'm using is:
private void setClassificationText(string classificationText, Word.WdColorIndex color)
{
//current mail item document
Word.Document document = (Word.Document)mailItem.GetInspector.WordEditor;
Word.Range rng = document.Paragraphs[1].Range;
//check if a classification level was already supplied
if (checkIfClassificationExists(rng))
{
//get the first 2 Paragraphs and remove the text from them
int paraCount = 2;
for (int i = 1; i <= paraCount; i++)
{
Word.Range classificationRange = document.Paragraphs[i].Range;
removeTextFromParagraph(classificationRange);
}
rng.Collapse();
rng = document.Paragraphs[1].Range;
}
rng.InsertBefore(classificationText + CT.lineFeedStr5 + CT.classification + classificationText + CT.lineFeedStr3);
//sets the color and text
rng.Font.ColorIndex = color;
rng.Text = CT.classification + rng.Text;
rng.Font.Bold = 1;
}
private void removeTextFromParagraph(Word.Range rng)
{
int wordCount = rng.Words.Count;
rng.Delete(Count: wordCount);
}
solved the issue i was having.
i used the following:
private void setClassificationText(string classificationText, Word.WdColorIndex color)
{
//current mail item document
Word.Document document = (Word.Document)mailItem.GetInspector.WordEditor;
Word.Range rng = document.Paragraphs[1].Range;
//check if a classification level was already supplied
if (checkIfClassificationExists(rng))
{
//get the first 2 Paragraphs and remove the text from them
int paraCount = 2;
for (int i = 1; i <= paraCount; i++)
{
Word.Range classificationRange = document.Paragraphs[i].Range;
removeTextFromParagraph(classificationRange);
}
rng.Collapse();
rng = document.Paragraphs[1].Range;
}
//insert the text
rng.InsertBefore(classificationText + CT.lineFeedStr5 + CT.classification + classificationText);
//sets the color and text
rng.Font.ColorIndex = color;
rng.Text = CT.classification + rng.Text;
rng.Font.Bold = 1;
//get the beginning and ending positions of the blank space
startPosition = rng.Start + getClassificationLength(classificationText);
endPosition = (int)startPosition + CT.lineFeedStr5.Length-1;
//get the Word.Range for the blank space
Word.Range rngNormal = document.Range(ref startPosition, endPosition);
//set blank space to be normal font (not bold and black)
rngNormal.Bold = 0;
rngNormal.Font.ColorIndex = Word.WdColorIndex.wdBlack;
}
private int getClassificationLength(string classificationText)
{
int returnValue = 0;
returnValue = CT.classification.Length + classificationText.Length;
return returnValue;
}
hope this can help someone else out.

RichTextBox different back color for each line

I am developing a windows form application using C#.Net. In part of my code I defined a function to log system events. Here is the body of this function:
richTextBoxLog.Text += "-";
richTextBoxLog.Text += some logs and strings ...;
richTextBoxLog.Text += "." + new string(' ', 1000) + Environment.NewLine;
richTextBoxLog.Select(richTextBoxLog.GetFirstCharIndexFromLine(logCounter), richTextBoxLog.Lines[logCounter].Length);
richTextBoxLog.SelectionBackColor = (logCounter % 2 == 0) ? Color.LightBlue: Color.LightGray;
logCounter++;
richTextBoxLog.ScrollToCaret();
the initial value of logCounter is zero (the line of first event refers to logCounter=0). For odd lines the back color should be Color.LightGray and for even lines it should be Color.LightBlue. However as you can see below it does not change the back color properly.
Each time this function is called (to add new text line) the region of richTextBoxLog.Select is updated according to the new line's start and end indices. But when an even line is added to the text box the back color of all of the previous lines turn into blue (even color).
I appreciate your help in advance.
Documentation http://msdn.microsoft.com/en-us/library/system.windows.forms.richtextbox.selectionbackcolor.aspx states:
Characters that are entered from that position have the specified SelectionBackColor.
Which seems likely to cause your issues. Although I still can't see how it influences previously added text.
Anyways, you can solve it by repainting all line colors when you add text:
richTextBoxLog.Text += "-";
richTextBoxLog.Text += some logs and strings ...;
richTextBoxLog.Text += "." + new string(' ', 1000) + Environment.NewLine;
var lineCount = 0;
foreach (var line in richTextBoxLog.Lines) {
richTextBoxLog.Select(richTextBoxLog.GetFirstCharIndexFromLine(lineCount), line.Length);
richTextBoxLog.SelectionBackColor = (lineCount % 2 == 0) ? Color.LightBlue : Color.LightGray;
lineCount++;
}
richTextBoxLog.ScrollToCaret();
It should be Helpfull:
public void AppendText(string text, Color color,Color backColor)
{
richTextBox1.SelectionStart = richTextBox1.TextLength;
richTextBox1.SelectionLength = 0;
richTextBox1.SelectionColor = color;
richTextBox1.AppendText(text);
richTextBox1.SelectionColor = richTextBox1.ForeColor;
richTextBox1.SelectionBackColor = backColor;
richTextBox1.ScrollToCaret();
}

Right Positioning For Context-Hint List (Intellisense)

just like this image from Avalon:
how to do the right positioning for a context-hint or intellisense?
senario:
im working on a code-editor and i use richtextbox(rtb) as the c-editor and the combobox(lb) as the context-hint .
all codes are almost done() except for right positioning for combobox(context hint) .
i use this code:
Point cursorPt = Cursor.Position;
lb.Location = PointToClient(cursorPt);
but its appearing when mouse cursor was ... if mouse cursor was outside the form it will not appear also .
further more heres the codes:
public void TextChangedEvent(object sender, EventArgs e)
{
lb.BringToFront();
RichTextBox rtb = sender as RichTextBox;
if (rtb != null)
{
//pass through to the HighlightType class
HighlighType HighlighType = new HighlighType(rtb);
lb.Visible = false;
lb.Items.Clear();
}
// Calculate the starting position of the current line.
int start = 0, end = 0;
for (start = rtb.SelectionStart - 1; start > 0; start--)
{
if (rtb.Text[start] == '\n') { start++; break; }
}
// Calculate the end position of the current line.
for (end = rtb.SelectionStart; end < rtb.Text.Length; end++)
{
if (rtb.Text[end] == '\n') break;
}
// Extract the current line that is being edited.
String line = rtb.Text.Substring(start, end - start);
// Backup the users current selection point.
int selectionStart = rtb.SelectionStart;
int selectionLength = rtb.SelectionLength;
// Split the line into tokens.
Regex r = new Regex("([ \\t{}();])");
Regex singlequote = new Regex("\'[^\"]*\'");
Regex doublequote = new Regex("\"[^\"]*\"");
string[] tokens = r.Split(line);
int index = start;
foreach (string token in tokens)
{
// Set the token's default color and font.
rtb.SelectionStart = index;
rtb.SelectionLength = token.Length;
rtb.SelectionColor = Color.Black;
rtb.SelectionFont = new Font("Courier New", 10, FontStyle.Regular);
if (token == "//" || token.StartsWith("//"))
{
// Find the start of the comment and then extract the whole comment.
int length = line.Length - (index - start);
string commentText = rtb.Text.Substring(index, length);
rtb.SelectionStart = index;
rtb.SelectionLength = length;
HighlighType.commentsType(rtb);
break;
}
//*** invention code:
Point cursorPt = Cursor.Position;
lb.Location = PointToClient(cursorPt);
KeyWord keywordsL = new KeyWord();
KeyWord eventsL = new KeyWord();
if (token == "." || token.StartsWith(".") & token.EndsWith(" "))
{
foreach (string str in keywordsL.keywords)
{
lb.Items.Add(str);
lb.Visible = true;
lb.Focus();
}
ty in advance!
Point point = this.rtb.GetPositionFromCharIndex(rtb.SelectionStart);
this.lb.Location = point;

Categories