How is it a bug? If you look at the discription, it gets the closest character. The closest character to the position you click is indeed the last letter. I haven't seen the source, but based on the description, it is working as intended.
In my brief look at the methods available to the RichTextBox
I didn't see one that would resolve the issue easily. Something you could do is pad the ending of the text with an actual character, eg: a space.
//...
string originalText = richTextBox1.Text;
richTextBox1.Text += " ";
//Your code to get the index and substring
//Return the textbox to its original state
richTextBox1.Text = originalText;
richTextBox1.SelectionLength = 0;
richTextBox1.SelectionStart = positionBegin;
That should do what you are looking for, but it is rather simple and will be inefficient depending on the amount of text you're dealing with. If you wanted to create a method that functions like the GetCharIndexFromPosition(Point pt)
, you will probably end up in the unmanaged code realm.
EDIT: Because I was curious (Extension method solution)
I started looking at the source code of the RichTextBox
control and it does indeed stop you from selecting a character outside the max length of the text length as seen here:
public override int GetCharIndexFromPosition(Point pt) {
NativeMethods.POINT wpt = new NativeMethods.POINT(pt.X, pt.Y);
int index = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.EM_CHARFROMPOS, 0, wpt);
string t = this.Text;
//This bit is stopping you from getting an index outside the length of the text
if (index >= t.Length) {
index = Math.Max(t.Length - 1, 0);
}
return index;
}
To "fix" this you can make a extension method that implements it the same way but remove the bit about checking to see if the index is larger than the length of the text:
public static class RichTextBoxExtensions
{
private const int EM_CHARFROMPOS = 0x00D7;
public static int GetTrueIndexPositionFromPoint(this RichTextBox rtb, Point pt)
{
POINT wpt = new POINT(pt.X, pt.Y);
int index = (int)SendMessage(new HandleRef(rtb, rtb.Handle), EM_CHARFROMPOS, 0, wpt);
return index;
}
[DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, POINT lParam);
}
[StructLayout(LayoutKind.Sequential)]
internal class POINT
{
public int x;
public int y;
public POINT()
{
}
public POINT(int x, int y)
{
this.x = x;
this.y = y;
}
}
With this you are back to your original code! Just change GetCharIndexFromPosition
to GetTrueIndexPositionFromPoint
and it will work as expected.