RichTextbox write in place to current line - c#

Clarification: I want to output line of text to the same "position" in a RichTextBox, replacing the previous line.
In C# Windows Forms Application trying to use RichTextBox for displaying messages. Most of the messages are appended, so that is fine but at one point in the program it has a counter, showing the amount of rows processed. For example like this:
Processed: 001 Records.
etc
well ... I don't need it to fill the RichTextBox with a thousands of lines like this:
Processed: 001 Records.
Processed: 002 Recoeds.
Instead I am trying to move the Caret to a start of the line and write the line again. Probably need to remove the previous line in a RichTextBox. Can't figure out how to always write to the same last line in RichTextBox.
I tried to use SelectionStart and ScrollToCaret() that did not work.

You could try something like this (rtb is your RichTextBox variable)
// Get the index of the last line in the richtextbox
int idx = rtb.Lines.Length - 1;
// Find the first char position of that line inside the text buffer
int first = rtb.GetFirstCharIndexFromLine(idx);
// Get the line length
int len = rtb.Lines[idx].Length;
// Select (Highlight) that text (from first to len chars)
rtb.SelectionStart = first;
rtb.SelectionLength = len;
// Replace that text with your update
rtb.SelectedText = "Processed: " + recordCount + " Records.";
No error handling added, but you could add some checks to be sure to stay inside the text buffer

One solution would be to store the current text before you start processing:
string oldText = richTextBox.Text;
for (int i = 0; i < X; i++)
{
// process stuff
richTextBox.Text = oldText + Environment.NewLine + "Processed: " + i + " Records.";
}
I believe that this method disregards the RTF data though, so you might use RichTextBox.Rtf instead.

Related

Using C# append text to each end of line of a flat file

How to I append text to end of a line in a flat file using c#? Basically, I'd like to append row numbers at the end of each line.
Just a quick refactor of MasterXD's solution:
var linesInText = stringWithText.Split(Environment.NewLine);
StringBuilder stringWithRowNumbers = new StringBuilder();
var row = 1;
foreach (var line in linesInText)
{
stringWithRowNumbers.Append(line);
stringWithRowNumbers.Append(row++);
stringWithRowNumbers.Append(Environment.NewLine);
}
string result = stringWithRowNumbers.ToString();
Using StringBuilder for this is going to perform much better than simple string concatenation and is considered a best practice in this use case.
Here is a quick one line version using Linq's Enumerable.Select with index and String.Join Method (String, String[]) to rebuild the lines.
string path = "Path to your flat file";
var numberedText = String.Join(Environment.NewLine, File.ReadAllLines(path).Select((line, index) => string.Join(" ", line.Trim(), index + 1)));
Console.WriteLine(numberedText);
The resulting string will have row numbers at the end of each line.
By flat file i suppose you mean a normal text file?
Firstly you'd want to split a piece of text into it's lines. This is done by the following means:
string[] linesInText = stringWithText.Split('\n');
The character \n represents a new line. So everytime a 'new line' is present, split there. The the fucction Split seperates a string into parts, where the seperator is given as the input. The parts will then be made into a string array. In this case, all the lines in the text or string willbe turned into an array.
Now you'd want to add the numbers to the end of each line. This can be done in the following way:
string stringWithRowNumbers = "";
for (int i = 0; i < linesInText.Length; i++) // Go through all lines
{
stringWithRowNumbers = linesInText[i] + "YourNumbers" + "\n"; // The old/first line + your numbers + new line
}
Now you should have a string with numbers in the end of all lines.
I hope this helps.
EDIT: I just realized you asked for row numbers. Here's the correct code.
string stringWithRowNumbers = "";
for (int i = 0; i < linesInText.Length; i++) // Go through all lines
{
// The space is intentional. If there is no space, then the number will not have any space between itself and the line
stringWithRowNumbers = linesInText[i] + " " + (i + 1) + "\n"; // The old/first line + row number + new line
}

Word count not working when entering new line

I've been looking at other stack overflow articles regarding similar issues when it comes to word count in C#, but none have helped me when it comes to the pickle I've encountered.
I have a textbox that inputs text from a text file. The text is split into three lines by me pressing the enter button to create a new line in a text file. The text reads:
It's a test to see "if" the
application_for Top Image Systems
actually work. Hopefully it does work.
Now as you can see there should be 17 words, however my word count only says 15. I have realized after a bit of trial and error that the issue must be the fact it's in a new line. Every time it goes to a new line, it thinks the last word of the previous line and the first word of the new line are together as a word (or that's what I think the program is thinking).
My question is with the code I have below, how can I get to recognize that if there is a new line, that it should split the words like a space?
Below is my code:
string nl = System.Environment.NewLine;
//Missing Code to read text file which I don't need to include in this example
do
{
textLine = textLine + txtReader.ReadLine();
}
//Read line until there is no more characters
while (txtReader.Peek() != -1);
//seperate certain characters in order to find words
char[] seperator = (" " + nl).ToCharArray();
//number of words
int numberOfWords = textLine.Split(seperator, StringSplitOptions.RemoveEmptyEntries).Length;
txtReader.ReadLine(); strips your newline away.
From the msdn:
The string that is returned does not contain the terminating carriage return or line feed.
so you have to add it manually (or just add a space)
textLine = textLine + txtReader.ReadLine() + " ";
consider using the StringBuilder class for repeated concatination of strings.
Edit:
To get the character count as if the spaces were never added, do:
int charCount = textLine.Length - lineCount;
where lineCount an integer that you increment every time you add a space in your do-while loop:
int lineCount = 0;
do
{
textLine = textLine + txtReader.ReadLine();
lineCount++;
}
I'm a bit of a beginner myself, sorry if this is not a great answer, but I've just done a bunch of text stuff in c# and I'd probably approach by replacing the line breaks which will show up as "\n" or "\r" in your original string with a space, " " - something like:
nl = nl.Replace("\r", " ");

c# how can I update just one line text in richtextbox?

how can I update just one line text in richtextbox?
String[] lines = richTextBox8.Lines;
lines[2] += " ";
richTextBox8.Lines = lines;
I am using this code part for update second line of richtextbox but it scans all my richtextbox lines and it takes many times.
so I want to update line text for 1 line.
How can I do that?
Note that you must never touch the Text or the Lines directly or all previous formatting gets messed up.
Here is a function that will solve the problem without messing up the formatting:
void changeLine(RichTextBox RTB, int line, string text)
{
int s1 = RTB.GetFirstCharIndexFromLine(line);
int s2 = line < RTB.Lines.Count() - 1 ?
RTB.GetFirstCharIndexFromLine(line+1) - 1 :
RTB.Text.Length;
RTB.Select(s1, s2 - s1);
RTB.SelectedText = text;
}
Note the in C# the numbering is zero beased, so to change the 1st line you call changeLine(yourrichTextBox, 0, yourNewText);
To only modify (not replace) the line you can simply access the Lines property; just make sure never to change it!
So to add a blank to the 2nd line you can write:
changeLine(yourrichTextBox, 1, yourrichTextBox.Lines[1] + " ");

Keep text positions after saving richtextbox to RTF file

i'm trying to create some RTF files from richtextbox content ( which is load from RTF files )
After opening file by some code and applying some changes and saving back new file (output) to another location. i find that positions text have changed and also font colors. please see attached captures for more clarifications.
input:
output:
desired ouput
I think i need to talk a bit about what i apply to input from the code: well i need to replace every variables begining by $ by some variables from databases:
I used this portion of code for that:
foreach (Match match in Regex.Matches(richTextBox1.Text, "(\\$\\w+)"))
{
if (match.Groups[1].Value.Substring(1).Equals("Add1"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, getAdress1(nums_res[j].ToString()));
if (match.Groups[1].Value.Substring(1).Equals("Add2"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, getAdress2(nums_res[j].ToString()));
if (match.Groups[1].Value.Substring(1).Equals("Add3"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, getAdress3(nums_res[j].ToString()));
if (match.Groups[1].Value.Substring(1).Equals("Add4"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, getLand(nums_res[j].ToString()));
if (match.Groups[1].Value.Substring(1).Equals("Rechnr"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, nums_res[j]);
if (match.Groups[1].Value.Substring(1).Equals("Datum"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, getDatum(nums_res[j].ToString()));
if (match.Groups[1].Value.Substring(1).Equals("resname"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, getName1(nums_res[j].ToString()));
if (match.Groups[1].Value.Substring(1).Equals("resvorname"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, getVorname(nums_res[j].ToString()));
if (match.Groups[1].Value.Substring(1).Equals("resroom"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, getZimmer(nums_res[j].ToString()));
if (match.Groups[1].Value.Substring(1).Equals("anz"))
richTextBox1.Text = richTextBox1.Text.Replace(match.Groups[1].Value, getAnz(nums_res[j].ToString()));
}
int indexToText = richTextBox1.Find(getAdress1(nums_res[j].ToString()));
int endIndex = richTextBox1.Find(getAdress1(nums_res[j].ToString()));
if(indexToText > 0 && endIndex > 0)
richTextBox1.Select(indexToText, endIndex); richTextBox1.SelectionAlignment = System.Windows.Forms.HorizontalAlignment.Center;
int indexToText2 = richTextBox1.Find(getLand(nums_res[j].ToString()));
int endIndex2 = richTextBox1.Find(getLand(nums_res[j].ToString()));
if (indexToText2 > 0 && endIndex2 > 0)
richTextBox1.Select(indexToText2, endIndex2); richTextBox1.SelectionAlignment = System.Windows.Forms.HorizontalAlignment.Center;
richTextBox1.SaveFile("d:\\ryadmogadoroutput" + nums_res[j].ToString());
i = i + 1;
richTextBox1.Clear();
for now i dont replace all of them but just some and i want to know where the difference comes between my output and desired output. ( as u can see, i tried to center first variables from the code)
i'm wondering if theres a way to keep original format of the file after applying the changed i talked about
Thank you
EDIT: After changing the property .text to rtf here the improved output. still some details to fix: font color, and some deplaced ( i dont know why ) strings, please see date:$datum
EDIT: solution suggestion by #TaW:
output:
compilation error:
I Think you should change the text format to RTF Format by changing "richTextBox1.Text" to "richTextBox1.RTF"
You must never change the Text directly after any formatting has been applied to the RichText. Instead you need to work strictly on the SelectedText using Copy, Paste, Append and the other specialized methods.
So at the very least you need to write an appropriate Replace function!
Maybe, with a little luck, not working on the Text but the Rtf property will also help, but it may be interwoven with formatting stuff that might be in the way..
Here is a function that will to do it :
void RtfReplace(RichTextBox RTB, Match match, string replace, ref int offset)
{
RTB.Select(match.Index + offset, match.Length);
RTB.SelectedText = replace;
offset += replace.Length - match.Length;
}
And a few respective calls
int offset = 0;
foreach (Match match in Regex.Matches(richTextBox1.Text, "(\\$\\w+)"))
{
if (match.Groups[1].Value.Substring(1).Equals("Add1"))
RtfReplace(richTextBox1, match, getAdress1(nums_res[j].ToString()), ref offset);
if (match.Groups[1].Value.Substring(1).Equals("Add2"))
RtfReplace(richTextBox1, match, getAdress2(nums_res[j].ToString()), ref offset);
//..
Update: Since each replacement is likely to change the length of the replaced piece of text we will need to adjust all positions in the matches collection by that difference (or repeatedly call the whole replacement code until no more matches are found.) The fix is simple, though..

How do you create a WYSIWYG TextBox control editor for vertically centered messages sent to a mobile device?

I have a WPF TextBox that holds seven lines of text and has word wrapping enbabled.
<TextBox TextWrapping="Wrap" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" MaxLines="7"/>
As you can see in the XAML above the text is centered vertically and horizontally. When I type a short phrase that fits on a single line, the text appears on the 4th line of the control as expected since the VerticalContentAlignment is "Center".
The text that is entered by the user is meant to be sent to a mobile device that has a display that holds seven lines of text and uses the "\n" to wrap to the next line. The intent is that the display of text on the mobile device looks the same as what is entered into the TextBox control. At least as far as number of lines of text, centering, and where line breaks occur.
So when the the user finishes entering the text into the TextBox control and clicks the "Send Message" button, some post-processing must be done on the entered text before sending it to the mobile device.
The text entered into TextBox control needs to have newline (\n) characters added wherever the text wraps to a new line in the TextBox control. For example, in cases where the control is showing multiple lines of text, I copy the TextBox's text and add a newline between the lines wehre the TextBox control wrapped the lines of text that were entered by the user.
So when the user clicks a "Send Message" button this is the code that does the post processing:
public static String AddNewLineCharsToMessage(TextBox textBox)
{
String message = String.Empty;
if (textBox == null) return message;
// First strip all the carriage returns and newline characters
// so we don't have duplicate newline characters in the message.
// Then add back in just the newline characters which is what the
// mobile device uses to wrap lines.
// Just assign the text if we have a single line message
if (textBox.LineCount < 2)
return textBox.Text;
var textLines = new List<string>(5);
int lineCount = Math.Min(textBox.LineCount, textBox.MaxLines);
for (Int32 index = 0; index < lineCount; index++)
{
if (textBox.GetLineText(index).Length > 0)
{
textLines.Add(textBox.GetLineText(index));
textLines[index] = textLines[index].Replace("\r", "");
textLines[index] = textLines[index].Replace("\n", "");
}
else
textLines.Add("\n");
}
message = String.Empty;
for (Int32 index = 0; index < lineCount; index++)
message += textLines[index] + (index < lineCount - 1 ? "\n" : "");
return message;
}
Given the code above, I would expect the output for a single line of text to look something like: "\n\n\n\nFoo". However, the output is "\nFoo\nFoo\nFoo\nFoo". Setting a break point in the code I see that textBox.GetLineText(index) for indices 0 through 3 returns "Foo" for each index even though "Foo" is only shown once in the TextBox control.
So I guess I really have two questions:
1) Why does GetLineText return a LineCount of 4 with every line having the same text, when only a single line of text (that fits on one line in the TextBox control) was entered by the user?
2) What is an easy way to work around this, keep the entered text centered in the TextBox control, and send the remote device the text message that will be displayed as seen by the user on the TextBox control?
Notes:
I cannot simply remove duplicate lines of text and replace them with "\n" as the user may have typed in the same text on multiple lines. Also, I could simply align the entered text to the vertical top instead of the vertical center. I have verified this works, but does not give a true WYSIWIG experience.
Looks like a bug in the method. You could work around this by either wrapping the textbox with another control that does the vertical centering or by extracting the lines via the text property.
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<TextBox AcceptsReturn="True" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" BorderThickness="0"> </TextBox>
</StackPanel>
The following modified code from the method shown above solves the problem. I am still curious however if Microsoft has a bug with the textBox.GetLineText method.
public static String AddNewLineCharsToMessage(TextBox textBox)
{
String message = String.Empty;
if (textBox == null) return message;
// Just assign the text if we have a single line message
if (textBox.LineCount < 2)
return textBox.Text;
// Find the index for the first line that contains text displayed in the TextBox.
// GetLineText(index) will return the text displayed/entered by the user for indices less
// than the index of the line that the text is actually displayed on. This seems to be
// a bug to me, but I will workaround this Microsoft weirdness.
// Find the index of first line that actually displays text by using the length of TextBox.Text
Int32 firstTextLineIndex = 0;
Int32 textLen = textBox.Text.Length;
Int32 textLinesLen = 0;
for (Int32 firstTextLine = textBox.LineCount - 1; firstTextLine >= 0; firstTextLine--)
{
textLinesLen += textBox.GetLineText(firstTextLine).Length;
if (textLinesLen >= textLen)
{
firstTextLineIndex = firstTextLine;
break;
}
}
// First strip all the carriage returns and newline characters
// so we don't have duplicate newline characters in the message.
// Then add back in just the newline characters which is what the car
// code uses to parse out the message to be displayed on each line.
var textLines = new List<string>(5);
int lineCount = Math.Min(textBox.LineCount, textBox.MaxLines);
for (Int32 index = 0; index < lineCount; index++)
{
if (index < firstTextLineIndex)
textLines.Add("");
else // if (textBox.GetLineText(index).Length > 0)
{
textLines.Add(textBox.GetLineText(index));
textLines[index] = textLines[index].Replace("\r", "");
textLines[index] = textLines[index].Replace("\n", "");
}
}
message = String.Empty;
for (Int32 index = 0; index < lineCount; index++)
message += textLines[index] + (index < lineCount - 1 ? "\n" : "");
return message;
}

Categories