I am struggling to move the caret in a textbox editing control within a DataGridView, one line up and one line down, just as a user would get when pressing up and down arrows.
So I don't mean lines as what is between newline characters, I mean lines as what is between the left and right side of a textbox.
I cannot use GetCharIndexFromPosition and GetPositionFromCharIndex because not all text will always be shown in the textbox display area.
Edit: I cannot simulate KeyPress because I am dealing with a textbox cell within a DataGridView. My aim is in fact getting arrow keys to do what they would do in a normal textbox, instead of jumping from row to row.
This should work.
Point pOld = textBox1.GetPositionFromCharIndex(textBox1.SelectionStart);
Point pNew = new Point(pOld.X, pOld.Y + textBox1.Font.Height)
int charIndex = textBox1.GetCharIndexFromPosition(pNew);
textBox1.SelectionStart = charIndex;
I don't think it's the cleanest solution though. Maybe you should look into the DataGridView properties/key handling.
The methods GetPositionFromCharIndex()
and GetCharIndexFromPosition()
have two limitations:
TextBox.SelectionStart
is the same for a caret at the end of a line and for a caret at the beginning of next line.To correct this, you can:
Another problem I encountered is that TextBox.Lines
refers to logic lines separated by new-line characters, while functions TextBox.GetLineFromCharIndex()
and TextBox.GetFirstCharIndexFromLine()
refer to visual lines as they are displayed in the textbox (that is, from side to side of TextBox, without there having to be new-line characters). Do not mix them up.
Resulting code (ugly as you may claim, but working) is as follows:
class Utils
{
[DllImport("user32.dll")]
static extern bool GetCaretPos(out System.Drawing.Point lpPoint);
public static void LineUp(TextBox tb)
{
int oldCharIndex = tb.SelectionStart;
int oldLineNo = tb.GetLineFromCharIndex(oldCharIndex);
System.Drawing.Point oldCharPos = tb.GetPositionFromCharIndex(oldCharIndex);
System.Drawing.Point oldCaretPos;
if (GetCaretPos(out oldCaretPos))
{
if (oldCharPos == oldCaretPos)
{
if (oldLineNo > 0)
{
tb.SelectionStart = tb.GetFirstCharIndexFromLine(oldLineNo - 1);
tb.ScrollToCaret();
System.Drawing.Point newPos = new System.Drawing.Point(oldCaretPos.X, oldCaretPos.Y - tb.Font.Height);
int newCharIndex = tb.GetCharIndexFromPosition(newPos);
if (tb.GetPositionFromCharIndex(newCharIndex).Y == newPos.Y)
{
tb.SelectionStart = newCharIndex;
}
else
{
tb.SelectionStart = tb.GetFirstCharIndexFromLine(oldLineNo - 1);
System.Windows.Forms.SendKeys.Send("{END}");
}
}
}
else
{
if (oldLineNo > 1)
{
tb.SelectionStart = tb.GetFirstCharIndexFromLine(oldLineNo - 2);
tb.ScrollToCaret();
System.Drawing.Point newPos = new System.Drawing.Point(oldCaretPos.X, oldCaretPos.Y - tb.Font.Height);
int newCharIndex = tb.GetCharIndexFromPosition(newPos);
if (tb.GetPositionFromCharIndex(newCharIndex).Y == newPos.Y)
{
tb.SelectionStart = newCharIndex;
}
else
{
tb.SelectionStart = tb.GetFirstCharIndexFromLine(oldLineNo - 2);
System.Windows.Forms.SendKeys.Send("{END}");
}
}
}
}
}
public static void LineDown(TextBox tb)
{
int oldCharIndex = tb.SelectionStart;
int oldLineNo = tb.GetLineFromCharIndex(oldCharIndex);
System.Drawing.Point oldCharPos = tb.GetPositionFromCharIndex(oldCharIndex);
System.Drawing.Point oldCaretPos;
if (GetCaretPos(out oldCaretPos))
{
if (oldCharPos == oldCaretPos)
{
if (oldLineNo < tb.GetLineFromCharIndex(tb.Text.Length - 1))
{
tb.SelectionStart = tb.GetFirstCharIndexFromLine(oldLineNo + 1);
tb.ScrollToCaret();
System.Drawing.Point newPos = new System.Drawing.Point(oldCaretPos.X, oldCaretPos.Y + tb.Font.Height);
int newCharIndex = tb.GetCharIndexFromPosition(newPos);
if (tb.GetPositionFromCharIndex(newCharIndex).Y == newPos.Y)
{
tb.SelectionStart = newCharIndex;
}
else
{
tb.SelectionStart = tb.GetFirstCharIndexFromLine(oldLineNo + 1);
System.Windows.Forms.SendKeys.Send("{END}");
}
}
}
else
{
System.Drawing.Point newPos = new System.Drawing.Point(oldCaretPos.X, oldCaretPos.Y + tb.Font.Height);
int newCharIndex = tb.GetCharIndexFromPosition(newPos);
if (tb.GetPositionFromCharIndex(newCharIndex).Y == newPos.Y)
{
tb.SelectionStart = newCharIndex;
}
else
{
tb.SelectionStart = tb.GetFirstCharIndexFromLine(oldLineNo);
System.Windows.Forms.SendKeys.Send("{END}");
}
}
}
}
}
Credit for the idea goes to this answer, and you may also want to take a look at MSDN reference on GetCaretPos and other Caret functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With