RichTextBox Help saving *custom* links - c#

I have implemented arbitrary links in my rtb using the CodeProject found here. The links are not truly links but instead data that is looked up when clicked and returned expanded information on the item clicked.
This all works great. The problem is when I try to save the data off to a database using the RichTextBox1.Rtf method the links are lost. I end up with the value of the text but there is no link data saved off in the Rtf. Is there no Rtf code for hyperlinks? Is there no way around this issue?
I am considering adjusting my approach to something more in line with this issue but I don't want to change everything around if I can find a way to save my custom hyperlinks.
Any suggestions would be great!
---------------UPDATE----------------
Before submitting I did a bit more digging and dug up this blog article which discusses that RTB do not save hyperlinks so I guess I am SOL. The only way around this is by saving off the text in hidden textbox and save that version to the db but that way gets clunky. I think I will go with the second option I found and I thought I would post this anyway since data in StackOverflow seems slim on this topic. Now I know why.

Since this is an old thread, I'll post this just for reference:
Here's a (somewhat) recent solution found in the comments of the same article on CodeProject:
Code:
/// <summary>
/// This additional code block checks the locations of links
/// and desc. it via a string which contains informations of how many links are there
/// .Split('&')-1 and the select information .Select(.Split('&')[i].Split('-')[0],.Split('&')[i].Split('-')[1])
/// After we select the links we can SetSelectionLink(true) to get our links back.
/// </summary>
public string getLinkPositions()
{
string pos = "";
for (int i = 0; i < this.TextLength; i++)
{
this.Select(i, 1);
int isLink = GetSelectionLink();
if (isLink == 1)
{
//the selected first character is a part of link, now find its last character
for (int j = i + 1; j <= this.TextLength; j++)
{
this.Select(j, 1);
isLink = GetSelectionLink();
if (isLink != 1 || j == this.TextLength)
{
//we found the last character's +1 so end char is (j-1), start char is (i)
pos += (i) + "-" + ((j - 1) - (i - 1)) + "&"; //j-1 to i but i inserted -1 one more so we can determine the right pos
i = j; //cont. from j+1
break; //exit second for cont. from i = j+1 (i will increase on new i value)
}
}
}
}
this.DeselectAll();
return pos;
}
/// <summary>
/// This method generates the links back only created via InsertLink(string text)
/// and overloaded InsertLink(string text,int position)
/// </summary>
/// <param name="pos">the pos string from getLinkPositions</param>
public void setLinkPositions(string pos)
{
string[] positions = pos.Split('&');
for (int i = 0; i < positions.Length - 1; i++)
{
string[] xy = positions[i].Split('-');
this.Select(Int32.Parse(xy[0]), Int32.Parse(xy[1]));
this.SetSelectionLink(true);
this.Select(Int32.Parse(xy[0]) + Int32.Parse(xy[1]), 0);
}
this.DeselectAll();
}
How to use the code [sic]:
when you are going to save the rtf, save the return string of getLinkPositions() to, when you want to load the rtf, just load it how you do, and then use the return string from 1st method to get the links bak
Ex :
Save:
some save var = richtext.rtf
additional save value = richtext.getLinkPositions();
Load back
richtext.rtf = some stream gets rtf
richtext.setLinkPositions(additional saved value from
some stream)

To summarize, Rich Text Boxes do not save hyperlinks in the .Rtf field (nor text). The value of the display is saved but not the actual link. Seems like a poor limitation to RTB's IMHO.
There are ways around this case, create custom links like this fellow did or re-evaluate your data on load searching for the keywords (the route I took since the data will never get too large to cause freezing).
The code I used to perform this is as follows and called on load:
foreach (ListViewItem keyword in Keywords.Items)
{
System.Text.RegularExpressions.Regex oKeyword = new System.Text.RegularExpressions.Regex(#"\b" + keyword.Text + #"\b");
foreach (System.Text.RegularExpressions.Match match in oKeyword.Matches(rtb.Text))
{
int index = match.Index;
int length = match.Length;
rtb.Select(index, length);
//This next bit is made available through the use of http://www.codeproject.com/Articles/9196/Links-with-arbitrary-text-in-a-RichTextBox
rtb.InsertLink(match.Value);
}
}

Well, another problem is, that the hyperlink is 'saved' but the click event and the target gets lost...
Only the format and behaviour (cursor changes) is restored.
And if You operate on this restored chunk of text it all gets messed up.
So before doin any 'restore' operations, You need to clean out the <hyperlink> stuff.
Prajakta Joshi made an example for autodetcting hyperlinks - it also contains a cleanup routine:
http://blogs.msdn.com/b/prajakta/archive/2006/10/17/autp-detecting-hyperlinks-in-richtextbox-part-i.aspx
Cheers, Stephan

As the Hyperlink tags don't get lost with saving, another approch would be to scan the loaded document for these tags and reapply it's properties - the click event and the navigate uri.
void restoreHyperlinks()
{
TextRange tr = new TextRange(_richTextBox.Document.ContentStart, _richTextBox.Document.ContentEnd);
TextPointer tp = tr.Start;
bool bFound = false;
foreach (System.Text.RegularExpressions.Match match in UrlRegex.Matches(tr.Text))
{
if (tp == null)
tp = tr.Start;
bFound = false;
while (tp != null && !bFound)
{
if (tp.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
{
string textRun = tp.GetTextInRun(LogicalDirection.Forward);
int indexInRun = textRun.IndexOf(match.Value);
if (indexInRun > -1)
{
bFound = true;
Inline parent = tp.Parent as Inline;
while (parent != null && !(parent is Hyperlink))
{
parent = parent.Parent as Inline;
}
if (parent is Hyperlink)
{
Hyperlink hyperlink = (Hyperlink)parent;
if (isHyperlink(match.Value))
{
Uri uri = new Uri(match.Value, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
{
uri = new Uri(#"http://" + match.Value, UriKind.Absolute);
}
if (uri != null)
{
hyperlink.NavigateUri = uri;
hyperlink.Click += Hyperlink_Click;
}
}
}
}
}
tp = tp.GetNextContextPosition(LogicalDirection.Forward);
}
}
}
The regex is:
private static readonly System.Text.RegularExpressions.Regex UrlRegex = new System.Text.RegularExpressions.Regex(#"(?#Protocol)(?:(?:ht|f)tp(?:s?)\:\/\/|~/|/)?(?#Username:Password)(?:\w+:\w+#)?(?#Subdomains)(?:(?:[-\w]+\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[\d]{1,5})?(?#Directories)(?:(?:(?:/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)?");
isHyperlink is another method for checking the URL - the code is taken from:
http://marcangers.com/detect-urls-add-hyperlinks-wpf-richtextbox-automatically/
Hope this helps!
Cheers, Stephan

Related

How to use RichTextBox.SelectionColor property to identify multiple text's background colors in C#?

I have a RichTextBox. I'm trying to code so that if a specific color is found in the SelectionBackColor property of the RTB, the background color of the words/ texts to be removed. For that, I need to detect if there exists multiple colors in the RTB. However, according to the documentation,
If the current text selection has more than one color specified, this property returns Color.Empty.
This is what I've tried so far:
private void randomBtn_Click(object sender, EventArgs e)
{
int startIndex = 0; //start from beginning of the richTextBox1
int endIndex = this.richTextBox1.TextLength; //until the end of all text available
this.richTextBox1.Select(startIndex, endIndex); //select from start until the end
if(endIndex != 0)
{
for(int i=startIndex; i< endIndex; i++)
{
if (this.richTextBox1.Text[i].ToString().Contains(" ")) //skips white spaces
{
continue;
}
else
{
while ((this.richTextBox1.BackColor != Color.Empty))
{
if (this.richTextBox1.SelectionBackColor.R == 155 && this.richTextBox1.SelectionBackColor.G == 255 && this.richTextBox1.SelectionBackColor.B == 255)
{
this.richTextBox1.HideSelection = true; //to prevent text highlighted
MessageBox.Show(this, "Texts with RGB(155, 255, 255) found!", "", MessageBoxButtons.OK);
break;
}
else
{
this.richTextBox1.HideSelection = true;
MessageBox.Show(this, "Error!", "", MessageBoxButtons.OK);
break;
}
}
}
}
}
else
{
MessageBox.Show(this, "richTextBox1 is empty!", "Alert!", MessageBoxButtons.OK);
}
}
To test, I added a breakpoint at the code containing the while line. Below shows the success and fail criterion,
The code works if:
There is no whitespace(at all)
There is only one color in the RTB
The code fails if:
There are whitespaces in between texts/ words/ characters
There are multiple colors in the RTB
Below shows the program execution examples:
This is when only one color is applied in the RTB(success),
This is when only one color and a whitespace are applied in the RTB(fail),
This is when multiple colors and whitespaces are applied in the RTB(fail),
So, is there any ways to override the return value of the SelectionColor property to be able to detect multiple colors, or are there any other ways of doing this? Just so you know, I've searched for this kind of problem over the internet, but I didn't think I've find any related issues.
It took me a while to figure out what #TaW meant in the comment section, but thanks to him, I've managed to solve this issue.
Actually, based on my reply in the comment section that I asked #TaW, what I thought as the same concept, was actually wrong. In the post above, what I did was entirely wrong:
I was supposed to assess each text one by one to know what their colors are. However, the codes below were already wrong to begin with.:
int startIndex = 0;
int endIndex = this.richTextBox1.TextLength;
this.richTextBox1.Select(startIndex, endIndex);
To analyze how RTB.SelectionColor, RTB.SelectionStart, and RTB.SelectionLength work, I decided to create another project. The project is a simple program containing an RTB, and some other buttons to manage the RTB's SelectionColor. If you want to check for the project that I've done, you're always welcomed to visit this link.
From "2", I re-used all the codes to suit the original project that I was working on. Now, it's all fine and working as it should.
To note, there are two important concepts/ ideas on managing the Selection property of the RTB.
If you are concerned of assessing each and every text in the RTB, you should code it like this:
private void methodA(RichTextBox localRTB)
{
//go through text one by one
int startIndex = 0;
int endIndex = localRTB.TextLength;
localRTB.SelectionStart = startIndex;
localRTB.SelectionLength = 1; //always 1 'cuz we want to assess each text one by one
while (localRTB.SelectionStart < endIndex)
{
//if the SelectionBackColor is red, change it to white
if (localRTB.SelectionBackColor == Color.Red) //take red color for example
{
localRTB.SelectionBackColor = Color.White;
}
//--manage bg color of selected text in RTB--
//so that able to go to next text
localRTB.SelectionStart += 1;
}
//finally...
localRTB.DeselectAll(); //unselect text in RTB
localRTB.Select(); //set focus back to the RTB
}
Below shows the result of the codes above(1):
If you don't really care about assessing each and every text in the RTB, you should code it like this instead:
private void methodB(RichTextBox localRTB)
{
int startIndex;
int endIndex;
if (localRTB.SelectionLength.Equals(0)) //if user don't select any text
{
startIndex = 0; //from beginning of RTB
endIndex = localRTB.TextLength; //'til the end of RTB
//--manage selected text in the RTB--
localRTB.SelectionStart = startIndex;
localRTB.SelectionLength = endIndex;
localRTB.Select(localRTB.SelectionStart, localRTB.SelectionLength);
//--manage selected text in the RTB--
}
else if (!(localRTB.SelectionLength.Equals(0))) //if user has text selected
{
startIndex = localRTB.SelectionStart; //from beginning of RTB
endIndex = localRTB.SelectionLength; //'til the end of RTB
if (localRTB.SelectedText.Contains(" ")) //skips whitespaces if selected together with text
{
if (localRTB.SelectedText.EndsWith(" "))
{
endIndex -= 1;
}
}
//--manage selected text in the RTB--
localRTB.Select(startIndex, endIndex);
//--manage selected text in the RTB--
}
}
Below shows the result of the codes above(2):
Peace...✌️

How to remove/delete Button text on when check button is clicked?

I am making this sum creator where user will have to type an answer using custom keyboard. and on check button click if answer is correct then new question is loaded.
My problem is after answering first question answer button reset to blank but when user types next answer, only one last alphabet is deleted (for example 5 from 15). and when i type 14 it shows 114 (1 from previously typed answer).
I need help to reset answer button text to blank.
I am using buttons because later i want to add more questions at the same time so user will have multiple answers to click and type.
Can anyone please help me on this? Also tell me if this is the right method to achieve what i want.
I am calling backspace function to delete previous answer and also setting text to blank.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Keyboard : MonoBehaviour
{
string word = null;
int wordIndex = -1;
string alpha = null;
string alpha2 = null;
public Text userAnswer1 = null;
public Text valueA, valueB;
public Text scoreCount;
private int a, b, answer1, score;
char[] nameChar = new char[5];
private void Start()
{
SumCreator();
}
public void nameFunc (string alphabet)
{
wordIndex++;
char[] keepchar = alphabet.ToCharArray();
nameChar[wordIndex] = keepchar[0];
alpha = nameChar[wordIndex].ToString();
word = word + alpha;
userAnswer1.text = word;
}
public void BackspaceFunction()
{
if (wordIndex >= 0)
{
wordIndex--;
alpha2 = null;
for (int i = 0; i < wordIndex + 1; i++)
{
alpha2 = alpha2 + nameChar[i].ToString();
}
word = alpha2;
userAnswer1.text = word;
}
}
public void SumCreator ()
{
a = Random.Range(0,15);
b = Random.Range(0,15);
answer1 = a + b;
valueA.text = a.ToString();
valueB.text = b.ToString();
scoreCount.text = "score " + score.ToString();
}
public void CheckAnswer()
{
Text buttonText = userAnswer1.GetComponentInChildren<Text>();
if (answer1 == int.Parse(userAnswer1.text))
{
score++;
// userAnswer1.text = string.Empty;
buttonText.text = string.Empty;
}
SumCreator();
}
}
I've edited my answer and removed the now irrelevant parts.
Once the button "Check" is clicked, first of all erase the text in the result textbox, then do the whole other logic.
To erase the text you can use next piece of code:
Text buttonText = buttonName.GetComponentInChildren<Text>();
buttonText.text = string.Empty;
You probably want to have this "buttonText" property as a global and get it once, at the start of the program instead of getting it every time the button is clicked. It won't do much difference in a small scale program, but it's a right way of thinking.
After checking your code a bit more, I can summarize your problem:
The whole logic of your program is flawed, there're many unnecessary complicated things which make it fail in several places. It is understandable, everybody goes through this stage, nothing to be ashamed or worried about. Either way it's my subjective opinion, which may be wrong.
Back to your code, all you have to do is update your result text, say "txtResult", once anything happens.
Once you click a number, do "txtResult += numberClicked".
Once you click backspace, remove last char of txtResult. Here is a question with many answers on how to do it, it's really simple.
Once you click "Check", in case it's the right number, set txtResult to empty.
Also, every time you update txtResult, you're supposed to update the UI too of course. Let's say you do it every time, it would be one line to update txtResult, and one line to update UI for each of the above 3 cases. So in total 6 lines. A check for an empty string while in "Backspace" function adds another line. My math could be wrong, but either way, it's quite short and simple approach, nothing too complicated.
You just lack relevant knowledge, otherwise you wouldn't be doing that nightmare in your Backspace function.
Regarding the "nameFunc" function, the whole 6 lines could be replaced with "txtResult += alphabet", isn't it? I'm not sure what you get in alphabet parameter, but either way, string is an array of chars, so you can also do "txtResult += alphabet[0]" instead of what you have there.
So, in total, you got it all right, the logic was right, you figured the main aspects. But you over complicated the whole thing. I believe you'll be fine after reading all this text, and wish you the best.
If you want to clear your Text object when you have succesfully entered your answer, you should not call your "BackSpace" function.
Just replace your code to this:
if (answer1 == int.Parse(userAnswer1.text))
{
score++;
userAnswer1.text = string.Empty;
This will clear the text element.
You could also look into using InputFields in Unity, which are designed for entering input and automatically support backspace and other keyboard functions.
If you do, make sure that you set the InputField's ContentType to either Integer Number or Decimal Number

Dialogue System C#

First thing first - I'm sorry for my poor English and I'm kinda new to this great community, so I'm really sorry if something is incorrect in my question.
In short - I've started with C# not so long ago (which means you find a lot of poor written code here) and now I'm aiming to create a dialogue system. Though I have some working sample, questions are:
How to make everything not this lame and improve the code;
Suggestions about improving performance;
Overall advices (maybe there is some more suitable tools for doing this);
Right now I use Finite-State Machine (FSM) as a general concept, so that every state is a dialogue scene. The last one is made of NPC quote and set of Player responds.
By now everything is pretty basic. Here I have my class for Player responds.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
namespace Testing
{
public class Player_Qoute : Label
{
public string Next_State { get; set; }//is used to tell, where to go next after choosing particular respond
}
It's inherited from Label and has one additional field - next stage number, which is added in function below:
private void NPC_Quote(string path, string specification, RichTextBox info)
{
StreamReader file = new StreamReader(path);//creating StremReader to read NPC quotes from .txt
string line = "";//Creating string variable to read from
try
{
while ((line = file.ReadLine()) != null)//readinf file line-by-line until the end
{
if (line.Contains(specification))//if line contains specified "tag"
{
line = line.Remove(0, specification.Length);//removing "tag" from line
info.Text += line + "\n";//adding NPC line to the output field
}
}
file.Close();
}
catch (Exception)
{
MessageBox.Show("Problem reading file");
}
}
This function parse through .txt file, searching for lines tagged "NPC_stage_n", where "n" - is a number of stage. This number is present at the end of every Player respond in .txt file and I put it in the "Next_Stage" field of Player_Quote objects.
The same idea is applied here, but now i dynamically create Player's responds (number of which varies from stage to stage). I'm facing some issues with appropriate placing of quotes on the GroupBox - sometimes they are missing a line or words, but I'm working on it:
void Quotes_Generation(string path, string specification, GroupBox parent)
{
parent.Controls.Clear();//deleting previous Player qoutes
int step = 0;//auxilary variable to separate quotes from each other by heigth
StreamReader file = new StreamReader(path);//StreamReader to read Player responds from .txt
string line = "";
while ((line = file.ReadLine()) != null)
{
if (line.Contains(specification))
{
Player_Qoute quote = new Player_Qoute();//inherited from Label;
quote.Name = "qoute_" + line.Remove(specification.Length, line.Length - specification.Length);
quote.Location = new Point(10, 20 + step);
quote.Size = new Size(360, 10);
quote.Text = line.Remove(0, specification.Length);//deleting "search tag" from text
quote.Text = quote.Text.Remove(quote.Text.Length-3, 3); //here we are deleting 3-digit number at the end of the string
//this number will show what is the next state of the dialogue if this Player respond is chosen.
quote.Next_State = line.Remove(0,line.Length - 3);//storing 3-digit number in Player_Quote property
using (Graphics g = CreateGraphics())//part of code which was borrowed from StackOverFlow and wasn't properly understood by me
{
SizeF size = g.MeasureString(quote.Text, quote.Font, 264);
quote.Height = (int)Math.Ceiling(size.Height);
quote.Text = quote.Text;
}
quote.MouseDown += new MouseEventHandler(this.Quote_Click);//creating event for choosing this respond
parent.Controls.Add(quote);//adding respond to GroupBox
step += (quote.Height+3);//increasing step
if (parent.Height < step)//enlarging GroupBox
{
parent.MaximumSize = new System.Drawing.Size(parent.Width, step + 50);
parent.Size = new System.Drawing.Size(parent.Width, step + 50);
}
}
}
file.Close();
}
And here is the Quote_Click event:
private void Quote_Click(object sender, EventArgs e)
{
Player_Qoute current = sender as Player_Qoute;//recognizing the sender
richTextBox1.Text += Player_Name + " - " + current.Text + "\n";//adding Player respond with Player name to RichTextBox
NPC_Quote(Application.StartupPath + "/Readme.txt", "NPC_stage_" + current.Next_State + ":", richTextBox1);//Adding new NPC line according to chosen respond
Quotes_Generation(Application.StartupPath + "/Readme.txt", "Player_stage_" + current.Next_State + ":", groupBox1);//refreshing responds according to previous actions
}
I'll appreciate all the advices!

How to invoke element in a WebBrowser by the class name(s)?

I'm trying to make a simple Facebook client. One of the features should allow the user to post content on the homepage/his profile.
It logs the user in (works fine, all of the elements have got ids on Facebook) and then inserts the data in the corresponding field (works fine as well), but then it needs to click the "Post" button. However, this button doesn't have any id. It only has got a class.
<li><button value="1" class="_42ft _4jy0 _11b _4jy3 _4jy1 selected _51sy" data-ft="{"tn":"+{"}" type="submit">Posten</button></li>
('Posten' is 'Post' on German.)
I've been looking around the internet for a few hours now and tried different solutions. My most current solution is to search the item by it's inner content ("Posten") and then invoke it. Doesn't work. It inserts the text but doesn't invoke the button. Here's the code:
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (postHomepage)
{
webBrowser1.Document.GetElementById("u_0_z").SetAttribute("value", metroTextBox1.Text);
GetButtonByInnerText("Posten").InvokeMember("click");
postHomepage = false;
}
}
HtmlElement GetButtonByInnerText(string SearchString)
{
String data = webBrowser1.DocumentText;
//Is the string contained in the website
int indexOfText = data.IndexOf(SearchString);
if (indexOfText < 0)
{
return null;
}
data = data.Remove(indexOfText); //Remove all text after the found text
//These strings are a list of website elements
//NOTE: These need to be updated with ALL elements from list such as:
// http://www.w3.org/TR/REC-html40/index/elements.html
string[] strings = { "<button" };
//Split the string with these elements.
//subtract 2 because -1 for index -1 for elements being 1 bigger than wanted
int index = (data.Split(strings, StringSplitOptions.None).Length - 2);
HtmlElement item = webBrowser1.Document.All[index];
//If the element is a div (which contains the search string
//we actually need the next item.
if (item.OuterHtml.Trim().ToLower().StartsWith("<li"))
item = webBrowser1.Document.All[index + 1];
//txtDebug.Text = index.ToString();
return item;
}
(This is a quick solution which I edited for my use, not very clean).
What's wrong here?
It does not look like your GetButtonByInnerText() method is searching for the button element correctly.
Here is simple replacement for you to try:
HtmlElement GetButtonByInnerText(string SearchString)
{
foreach (HtmlElement el in webBrowser1.Document.All)
if (el.InnerText==SearchString)
return el;
}

Wpf Richtextbox selection starting column and row number returns different values

I am initializing my Richtextbox,
void InitRTBFlowDocument()
{
Style noSpaceStyle = new Style(typeof(Paragraph));
noSpaceStyle.Setters.Add(new Setter(Paragraph.MarginProperty, new Thickness(0)));
rtbTextEditor.Resources.Add(typeof(Paragraph), noSpaceStyle);
}
I want to get Richtext box selection words row and column numbers. I wrote the code as follows, First time it is returning correctly.
void rtbTextEditor_SelectionChanged(object sender, RoutedEventArgs e)
{
//Get the richtext box selected text
Init.RTBSelectionText = rtbTextEditor.Selection.Text.Trim();
Init.SelectionText = rtbTextEditor.Selection.Text.Trim();
Init.isSelect = true;
if (Init.RTBSelectionText != string.Empty)
{
TextPointer tp = rtbTextEditor.Selection.Start.GetPositionAtOffset(-2, LogicalDirection.Forward);
if (tp != null)
GetStartingIndex();
}
Init.RTBContent = new TextRange(rtbTextEditor.Document.ContentStart, rtbTextEditor.Document.ContentEnd).Text;
}
void GetStartingIndex()
{
TextPointer tp1 = rtbTextEditor.Selection.Start.GetLineStartPosition(0);
TextPointer tp2 = rtbTextEditor.Selection.Start;
int SelectionColumnIndex = tp1.GetOffsetToPosition(tp2)-1;//column number
int someBigNumber = int.MaxValue;
int lineMoved;
rtbTextEditor.Selection.Start.GetLineStartPosition(-someBigNumber, out lineMoved); //Line number
int SelectionRowIndex = -lineMoved;
Init.RTBTextPoint = new RTBTextPointer();
Init.RTBTextPoint.Row = SelectionRowIndex;
Init.RTBTextPoint.Column = SelectionColumnIndex;
}
After clearing and added new content, The position returns wrong number,
public void DisplayContent(string content)
{
//Clear the rich text box
rtbTextEditor.Document.Blocks.Clear();
rtbTextEditor.Document.Blocks.Add(new Paragraph(new Run(content)));
}
Is anything rong in the above code.
Please help me
Thanks in advance!
This is because the contents in the RTB does not only contain text, it contains these things called TextPointerContext's. TextPointer's take this into account. You can check what the TextPointer is adjacent to by using:
TextPointer.GetPointerContext(LogicalDirection);
To get the next TextPointer:
TextPointer.GetNextContextPosition(LogicalDirection);
Some sample code I used in a recent project, this makes sure that the pointer context is of type Text:
while (start.GetPointerContext(LogicalDirection.Forward)
!= TextPointerContext.Text)
{
start = start.GetNextContextPosition(LogicalDirection.Forward);
if (start == null) return;
}
When you clear your RTB, you're probably removing some of these pointer contexts. So be careful when using GetPositionAtOffset(). This should give you a "pointer" in the right direction. If you need any more help me know.
Good hunting!

Categories

Resources