メソッドGetPositionFromCharIndex()
と には、次のGetCharIndexFromPosition()
2 つの制限があります。
- テキストボックスの境界を超えるテキストでは機能しません
- の文字インデックスは
TextBox.SelectionStart
、行末のキャレットと次の行の先頭のキャレットで同じです。
これを修正するには、次のことができます。
- 上記のメソッドを使用する前に、テキストボックスをスクロールして関連する行を表示します。
- user32.dll の GetCaretPos 関数を使用して、SelectionStart の位置と比較します。それらが等しくない場合、キャレットが行末にあることを意味します。
- 行末にキャレットを配置する {END} キーの押下をシミュレートします。
私が遭遇したもう1つの問題は、TextBox.Lines
改行文字で区切られた論理行を参照し、関数TextBox.GetLineFromCharIndex()
とTextBox.GetFirstCharIndexFromLine()
テキストボックスに表示される視覚的な行を参照することです(つまり、改行がなくてもTextBoxの左右に表示されます)。文字)。それらを混同しないでください。
結果のコード (あなたが主張するかもしれませんが、動作します) は次のとおりです。
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}");
}
}
}
}
}
アイデアの功績はこの回答にあり、 GetCaretPosおよびその他の Caret 関数に関する MSDN リファレンスも参照してください。