Keep text positions after saving richtextbox to RTF file - c#

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..

Related

String.IndexOf function giving incorrect position number for TextBox.Select

I found a strange behavior in indexOf functionality in my code, My string input is from read from a text file, when I search some text in the firstline of the code indexOf function correctly identify the position of the sub-string, but if I search some text in the second line it returns one character after the exact match, if I search something in the 3rd line it is returning 2 character position after the exact match, this is changing in the same pattern with every new line. I don't know why this is happening, I need to find a way to get the exact same position of the text.
My Code:
string fileContent = File.ReadAllText(filename);
string display_string = "";
txtOriginalText.Text = fileContent;
HighlightText(fileContent.IndexOf("projection"), 5, Color.Aqua);
display_string += fileContent.IndexOf("projection").ToString() + '\n';
HighlightText(fileContent.IndexOf("component"), 5, Color.LightGreen);
display_string += fileContent.IndexOf("component").ToString() + '\n';
HighlightText(fileContent.IndexOf("layer"), 5, Color.Pink);
display_string += fileContent.IndexOf("layer").ToString() + '\n';
txtModifiedText.Text = display_string;
Highlight function
private void HighlightText(int startIndex, int textLength, Color state)
{
txtOriginalText.Select(startIndex, textLength);
txtOriginalText.SelectionBackColor = state;
}
Image:
I tested this with a RichTextBox:
richTextBox1.Text = "test\r\ntest\r\ntest\r\n";
When you debug and check richTextBox1.Text after that line, its value is "test\ntest\ntest\n".
So it seems the RichTextBox removes the \r from your string (which as a Windows file content probably contains new line characters as \r\n).
As an immediate work around you should use IndexOf on txtOriginalText.Text instead of fileContent.

RichTextbox write in place to current line

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.

How to make a Following Character by using (anyword+'་') ,then make a next new line in WinForm using c#?

How to create custom word wrap with custom character. ie. I want to wrap the text using .(dot) character instead of space.
I am doing a project on word wrapping in richTextBox using c# WinForm, therefore I need to work the wordwrapping with (anyword+'་')together and then make the next new line because my problem is after every word wrapping '་' is coming at beginning/starting of the new line as shown in below example, '་' should come at every ending line
Suppose i have given origin string like:
རྒྱ་གར་ཚོང་པའི་ལྷན་ཚོགས་དངོས་སུ
Once I used the wordwrap concept, Its coming like this
རྒྱ་གར་ཚོང་པའི // we assume that this is first line
་ལྷན་ཚོགས་དངོས་སུ//this is second line and second line start with '་' so ending line should stay (anyword+'་') before break the line and it should happen for linewise.
so to avoid this problem I thought of doing the concept of "following character". After so many googling and browsing I have found following threads that what am i looking for, but sadly they are using different tools and Platforms. I have try lots using these concept and achieve my project using C#(WinForm) but couldn't work. Therefore kindly share me your threads and help me out to do this my project using c# (WinForm). Your kind help meant me lots.
https://www.youtube.com/watch?v=uTajI2lWwgE
http://www.c-sharpcorner.com/UploadFile/72d20e/canvas-text-wrapping-using-html-5/
Thank You!
if you wish to add new line after every . than you need to replace the text i.e. anyword. anyword to anyword.\r\nanyword where the \r\n is the sequence for new line. but, it may create some problem like if you write M.B.B.S. then it may be like M.\r\nB.\r\nB.\r\nS.\r\n.
string str = "This is the simple text. Hello world".Replace(". ", ".\r\n");
OUTPUT:
This is the simple text.
Hello world.
EDITED:
int tmpIndex = 0;
int startIndex = 0;
int lastIndex = 0;
string sChar = ".";
string strText = richTextBox1.Text;
Graphics g = this.CreateGraphics();
StringBuilder sb = new StringBuilder();
while (tmpIndex > -1)
{
lastIndex = tmpIndex;
tmpIndex = strText.IndexOf(sChar, tmpIndex + 1);
if (tmpIndex < 0)
tmpIndex = strText.Length - 1;
if (g.MeasureString(strText.Substring(startIndex, tmpIndex - startIndex), richTextBox1.Font).Width > richTextBox1.Width || tmpIndex == (strText.Length-1))
{
sb.AppendLine(strText.Substring(startIndex, lastIndex - startIndex));
startIndex = lastIndex;
if (tmpIndex == (strText.Length - 1))
break;
tmpIndex = lastIndex;
}
}
richTextBox1.Text = sb.ToString();

RichTextBox SelectionStart offset with linebreaks

I'm using a RichTextBox for coloured text. Let's assume I want to use different colours for different portions of the text. This is working fine so far.
I'm currently having a problem with the SelectionStart property of the RichTextBox. I've set some text to the Text property of the RichTextBox. If the text contains \r\n\r\n the SelectionStart Position won't match the position of characters with the assigned String.
Small example (WinformsApplication. Form with a RichTextBox):
public Form1()
{
InitializeComponent();
String sentence1 = "This is the first sentence.";
String sentence2 = "This is the second sentence";
String text = sentence1 + "\r\n\r\n" + sentence2;
int start1 = text.IndexOf(sentence1);
int start2 = text.IndexOf(sentence2);
this.richTextBox1.Text = text;
String subString1 = text.Substring(start1, sentence1.Length);
String subString2 = text.Substring(start2, sentence2.Length);
bool match1 = (sentence1 == subString1); // true
bool match2 = (sentence2 == subString2); // true
this.richTextBox1.SelectionStart = start1;
this.richTextBox1.SelectionLength = sentence1.Length;
this.richTextBox1.SelectionColor = Color.Red;
this.richTextBox1.SelectionStart = start2;
this.richTextBox1.SelectionLength = sentence2.Length;
this.richTextBox1.SelectionColor = Color.Blue;
}
The RichTextBox looks like this:
As you can see, the first two characters of the second sentence are not coloured. This is the result of an offset produced by \r\n\r\n.
What is the reason for this? Should I use another control for colouring text?
How do I fix the problem in a reliable way? I've tried replacing the "\r\n\r\n"with a String.Empty, but that produces other offset problem.
Related question:
Inconsistent behaviour between in RichTextBox.Select with SubString method
It seems that the sequence \r\n counts for one character only when doing selections. You can do the measurements in a copy of the string where all \r\n are replaced by \n.
Just for completeness (I'll stick to linepogls answer for now):
I've found another way to get indices for the SelectionStart property. The RichTextBox offers a Find method, that can be used to retrieve index positions based on a specified string.
Be aware of the fact, that the text you want to highlight might not be unique and occur multiple times. You can use an overload to specify a start position for the search.

Clipboard can copy a few words?

I'm weak in English so I hope you will understand this.
I learned yesterday that Clipboard is copy.
//textBox1.Text = "My name is not exciting";
Clipboard.SetText(textBox1.Text);
textBox2.Text = Clipboard.GetText();
This code copies your everything from the textbox1 and paste it in textbox2 right?
So it's possible to copy only a few words from textbox1 and paste it in textbox2?
If you don't understand, I'm want copy only a few words not all the line.
Even if this high level code still bring me :)
Clipboard.GetText(); will return the raw copied elements.
What you can do is save them to some variable:
string text = Clipboard().GetText();
Then do something with text, to get the elements you need:
textBox2.Text = text.Substring(0, 10); // An example.
The main idea to take away from this is, GetText() will give you a string. It's up to you to slice and dice that string any way you see fit and then make use of the results.
You don't need the Clipboard for this. Your user won't like that ;)
Just create a variable like this:
string box1Content = textBox1.Text;
textBox2.Text = boxContent;
You can even skip that variable.
If you really want to use the clipboard, your way is doing that.
For just getting some text out of the textbox you can either use substring or regular expressions.
http://msdn.microsoft.com/en-us/library/aka44szs.aspx
Good luck
Daniel, the substring method is a good one to use. You simply tell it where you want to take a piece of your text and it will create a new string of just that.
textBox1.Text = "MY name is not exciting";
//pretend you only want "not exciting" to show
int index = textBox1.Text.IndexOf("not");//get the index of where "not" shows up so you can cut away starting on that word.
string partofText = textBox1.Text.Substring(index);//substring uses the index (in this case, index of "not") to take a piece of the text.
Clipboard.SetText(partofText);
textBox2.Text = Clipboard.GetText();
To my mind is better idea to take selected text from text box.
I'm not sure witch kind of text box you are using but so show example on WPF you should use TextBox.SelectedText property.
I like linq. :-)
This is a example for splitting the string, enumerable it and concats in one:
textBox1.Text = "My name is not exciting";
int firstWord = 2;
int lastWord = 4;
string[] wordList = textBox1.Text.Split(new[] { ' ', '.', ',' }, StringSplitOptions.RemoveEmptyEntries);
string newText = string.Concat(wordList.Where((word, count) => count >= firstWord - 1 && count < lastWord).Select(w => w + " ")).TrimEnd();
Clipboard.SetText(newText);
textBox2.Text = Clipboard.GetText();
// Result: "name is not"
Edit: and without Clipboard you can use simply this Line
textBox2.Text = newText;

Categories