该方法GetPositionFromCharIndex()
有GetCharIndexFromPosition()
两个限制:
- 它们不适用于超出文本框边界的文本
- 的字符索引
TextBox.SelectionStart
对于行尾的插入符号和下一行开头的插入符号是相同的。
要纠正此问题,您可以:
- 在使用上述方法之前,滚动文本框以显示相关行。
- 使用 user32.dll 中的 GetCaretPos 函数将其与 SelectionStart 的位置进行比较。如果它们不相等,则表示插入符号位于行尾。
- 模拟 {END} 键按下以将插入符号定位在行尾。
我遇到的另一个问题是TextBox.Lines
指用换行符分隔的逻辑行,而函数TextBox.GetLineFromCharIndex()
和TextBox.GetFirstCharIndexFromLine()
指的是在文本框中显示的视觉线(即从文本框的一侧到另一侧,不必有换行符人物)。不要把它们混在一起。
生成的代码(你可能声称丑陋,但有效)如下:
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}");
}
}
}
}
}
这个想法的功劳归功于这个答案,您可能还想看看MSDN 参考上的 GetCaretPos和其他 Caret 函数。