RichTextBox: Find corresponding index - c#

Say I have a WPF RichTextBox with the following content:
Hello Hello // <== here is a line break \r\n
Turn Your Radio On!
I then read the text from the box with the following code:
public static string GetText(this RichTextBox box)
{
var range = new TextRange(box.Document.ContentStart,
box.Document.ContentEnd);
return range.Text;
}
After that I retrieve var index = text.IndexOf("Hello\r\nTurn") and var length = "Hello\r\nTurn".Length.
Based on index and length:
How can I select that text in the RichTextBox? The index/length in the plain string does not match up with what the RichTextBox expects.
I tried the approach from the answer here, but this does not seem to work if the text contains a line wrap / paragraph.
Note: My string manipulation (finding index / length) is considerably more complex than the example, but the example given here describes my problem well

The RichTextBox has a Selection property that you can call its "Select" method.
It accepts 2 TextPointer objects, one for the selection start and the other for its end.
http://msdn.microsoft.com/en-us/library/system.windows.documents.textrange.select.aspx
I don't think you the index and length properties will be good enough for you to select the text. You would have to get the real TextPointer.
Try using a method for finding specific words TextPointers such as the one specified in here -
http://blogs.microsoft.co.il/blogs/tamir/archive/2006/12/14/RichTextBox-syntax-highlighting.aspx

Related

RichTextBox inserting text

For Windows Forms.
I am trying to insert text into the .rtf field of a RichTextBox.
I have tried two methods. When I use .Rtf.insert, nothing happens at all.
When I edit the .rtf string based on the selected text positions myself, I either end up adding gibberish to the thing or getting an error that says that the file format is invalid. My best guess is that this is because the .rtf string is in .rtf format and the selection index that I am using is based on the plain text string and so I am inserting the text in the wrong location in the .rtf string and messing up the RTF code.
But knowing what the problem is (if I am correct) hasn't helped me solve it.
Is there a way to get .rtf.insert to work correctly, or is there a way to translate the selected text indexes to the actual .rtf text positions so that something like the code below would work? I am assuming that the RichTextBox itself must know how to translate the one index into another because it can insert characters when the user types just fine.
Here is my code snippet. The point of the code is to insert a marker into the text that will later be parsed and replaced with a student's first name. There will be other such codes. "codeLeader" and "codeEnder" are just the strings I use to surround the codes with. In this case I am using "[*" and *]" to indicate that there is a code I will need to parse, but I put them into separate strings so that I can easily change it if I wish. I have actually already written the parsing code, which works just fine on rich text. It is just inserting the text into the richTextBox itself that is the problem. In other words, if I were to type the codes by hand it would work just fine. But this would be troublesome for the user because some of the codes will use index numbers.
private void studentFirstNameCode_Click(object sender, EventArgs e)
{
string ins = f1ref.codeLeader;
ins += "SNFirst" + f1ref.codeEnder;
int start = editorField.richTextBox1.SelectionStart;
if (start == -1) { start = 0; }
int end = start + editorField.richTextBox1.SelectionLength;
if (end == -1) { end = 0; }
string pre = editorField.richTextBox1.Rtf.Substring(0, start);
string post = editorField.richTextBox1.Rtf.Substring(end);
string newstring = pre + ins + post;
editorField.richTextBox1.Rtf = newstring;
// this also doesn't work. gives no result at all.
// editorField.richTextBox1.Rtf.Insert(start, newstring);
}
I don't think that you need to use the RTF property to simple insert a text inside the RichTextBox actual text. In particular because you don't seem to add an RTF formatted text.
If you don't want to use RTF then the simplest way to accomplish your goal is just one line of code
editorField.SelectedText = yourParameterText;
This will work as you have pasted the text from the clipboard in the selected position (eventually replacing text if something is selected) and the base work of correctly formatting your text inside the RTF is done by the control itself
I have found a work-around by using .SendKeys. This makes the text appear a bit slowly (as if typed very quickly) so isn't optimal, but it does work.
It is enough for a workable solution, but I am still troubled by the problem. It seems like this issue should have a more elegant solution than this.

(WinRT)How to get TextBox caret index?

I got some problems with getting caret index of TextBox in Windows Store App(WP 8.1).
I need to insert specific symbols to the text when button is pressed.
I tried this:
text.Text = text.Text.Insert(text.SelectionStart, "~");
But this code inserts symbol to the beginning of text, not to the place where caret is.
UPDATE
I updated my code thanks to Ladi. But now I got another problem: I'm building HMTL editor app so my default TextBlock.Text is: <!DOCTYPE html>\r\n<html>\r\n<head>\r\n</head>\r\n<body>\r\n</body>\r\n</html>
So for example when user inserts symbol to line 3, symbol is inserted 2 symbols before caret; 3 syms before when caret is in line 4 and so on. Inserting works properly when symbol is inserted to the first line.
Here's my inserting code:
Index = HTMLBox.SelectionStart;
HTMLBox.Text = HTMLBox.Text.Insert(Index, (sender as AppBarButton).Label);
HTMLBox.Focus(Windows.UI.Xaml.FocusState.Keyboard);
HTMLBox.Select(Index+1,0);
So how to solve this? I guess new line chars making trouble.
For your first issue I assume you changed the TextBox.Text before accessing SelectionStart. When you set the text.Text, text.SelectionStart is reset to 0.
Regarding your second issue related to new lines.
You could say that what you observe is by design. SelectionStart will count one "\r\n" as one character for reasons explained here (see Remarks section). On the other hand, method string.Insert does not care about that aspect and counts "\r\n" as two characters.
You need to change slightly your code. You cannot use the value of SelectionStart as the insert position. You need to calculate the insert position accounting for this behavior of SelectionStart.
Here is a verbose code sample with a potential solution.
// normalizedText will allow you to separate the text before
// the caret even without knowing how many new line characters you have.
string normalizedText = text.Text.Replace("\r\n", "\n");
string textBeforeCaret = normalizedText.Substring(0, text.SelectionStart);
// Now that you have the text before the caret you can count the new lines.
// that need to be accounted for.
int newLineCount = textBeforeCaret.Count(c => c == '\n');
// Knowing the new lines you can calculate the insert position.
int insertPosition = text.SelectionStart + newLineCount;
text.Text = text.Text.Insert(insertPosition, "~");
Also you should make sure that SelectionStart does not exhibit similar behavior with other combinations beside "\r\n". If it does you will need to update the code above.

Replacing part of text in richtextbox

I need to compare a value in a string to what user typed in a richtextbox.
For example: if a richtextbox holds string rtbText = "aaaka" and I compare this to another variable string comparable = "ka"(I want it to compare backwards). I want the last 2 letters from rtbText (comparable has only 2 letters) to be replaced with something that was predetermined(doesn't really matter what).
So rtbText should look like this:
rtbText = "aaa(something)"
This doesn't really have to be compared it can just count letters in comparable and based on that it can remove 2 letters from rtbText and replace them with something else.
UPDATE:
Here is what I have:
int coLen = comparable.Length;
comparable = null;
TextPointer caretBack = rtb.CaretPosition.GetPositionAtOffset(coLen, LogicalDirection.Backward);
TextRange rtbText = new TextRange(rtb.CaretPosition, caretBack);
string text = rtbText.Text;
rtbText returns an empty string or I get an error for everything longer than 3 characters. What am I doing wrong?
Let me elaborate it a little bit further. I have a listbox that holds replacements for values that user types in rtb. The values(replacements) are coming from there, meaning that I don't really need to go through the whole text to check values. I just need to check the values right before caret. I am comparing these values to what I have stored in another variable (comparable).
Please let me know if you don't understand something.
I did my best to explain what needs to be done.
Thank you
You could use Regex.Replace.
// this replaces all occurances of "ka" with "Replacement"
Regex replace = new Regex("ka");
string result = replace.Replace("aaaka","Replacemenet");
gumenimeda, I had similar problems few weeks ago. I found my self doing the following (I asume you will have more than one occurance in the RichTextBox that you will need to change), note that I did it for Windows Forms where I have access directly to the Rtf text of the control, not quite sure if it will work well in your scenario:
I find all the occurancies of the string (using IndexOf for example) and store them in a List for example.
Sort the list in descending order (max index goes first, the one before him second, etc)
Start replacing the occurancies directly in the RichTextBox, by removing the characters I don't need and appending the characters I need.
The sorting in step 2 is necessary as we always want to start from the last occurance going up to the first. Starting from the first occurance or any other and going down will have an unpleasant surprise - if the length of the chunk you want to remove and the length of the chunk you want to append are different in length, the string will be modified and all other occurancies will be invalid (for example if the second occurance was in at position 12 and your new string is 2 characters longer than the original, it will become 14th). This is not an issue if we go from the last to the first occurance as the change in string will not affect the next occurance in the list).
Ofcourse I can not be sure that this is the fastest way that can be used to achieve the desired result. It's just what I came up with and what worked for me.
Good luck!

removing RichTextBox lines while keeping the colour of remaining lines in C#

Consider a RichTextBox which has 400 lines and includes a number of words and lines in diffident colours.
Is it possible to remove the first 100 lines of this text box, while the colour of remaining words are reserved. Currently, I am using the below code to remove lines, but It is not able to keep colours.
if (rtb.Lines.Count() > 400)
rtb.Lines = rtb.Lines.Skip(100).ToArray();
Use the SelectionText property. First select the lines you want to remove, then remove them by setting SelectionText to an empty string. Like this:
richTextBox1.SelectionStart = 0;
richTextBox1.SelectionLength = richTextBox1.GetFirstCharIndexFromLine(200);
richTextBox1.SelectedText = "";
This preserves the formatting of all the other lines. This can cause visible flicker on the UI, you can suppress that by implementing the Begin/EndUpdate methods as shown here.
You can't use the Lines property if you want to preserve the formatting. Lines is derived from TextBoxBase. You need to use the Rtf property and parse the lines yourself in the string you get back. If you want to just get the line count and then parse the RTF then you could do something like:
// NOTE: I am using Length rather than Count() because the array already knows its length
if (rtb.Lines.Length > 400)
{
// Parse the rtf here to remove the unwanted lines and preserve the format
}
You would need to look at the RTF specification to accurately pull out the actual lines. A line break is indicated by the tag \par. The line that would be tricky to deal with is the first line because it may contain extra information before the actual first line text.
.SelectedText = "" throws a Windows ding in my application
So I found a second solution which is to play with .Lines property
if (nbLines > maxLines)
{
Array.Copy(rtfBox.Lines, 1,
rtfBox.Lines, 0, rtfBox.Lines.Length - 1);
}

How to display char in grid lines using c#

I am working on a desktop application develop in C#. what i want to do is to:
Open a text file(.txt) Read Data Line By Line Create a grid type structure(i.e combination of
horizontal and vertical line) Then take first line and display its each char in single cell And the take second line and display its each char in single cell and so on.
Since i am beginner so i don't have any idea that how to acheive this. I only want some suggestions and guidance.
Well, this is actually easy to do provided you compose the correct items together to get your result.
You'll want to look up File operations, string manipulation (as well as the knowledge that a string is nothing but an enumerable of chars), and then some simple looping to get what you want.
At a high level, you'll just be needing to get the math right to display your set of text as a grid in X columns by Y rows.
Use File.ReadAllLines(). It will give you and array of strings - line by line.
For each string returned by ReadAllLines use string.ToCharArray. It will give you an array of symbols in string.
Update:
Number of columns in grid will be equal to max length of char array. Number of rows - to number of lines. Hope, I understood your task correctly.
Sounds like a homework problem?
Use the File class to read your text file. As far as printing the output to the screen, you have many options...if you're building a console application the you could just write characters to the output using the Console methods.
Hint: to split each line of text into characters, use the ToCharArray() method on the String class.
here is how you can read from a text file line by line
int counter = 0;
string line;
// Read the file and display it line by line.
System.IO.StreamReader file =
new System.IO.StreamReader("c:\\test.txt");
while((line = file.ReadLine()) != null)
{
Console.WriteLine (line);
counter++;
}
file.Close();
// Suspend the screen.
Console.ReadLine();
http://msdn.microsoft.com/en-us/library/aa287535(v=vs.71).aspx

Categories