以编程方式在文本框中移动插入符号,排列和向下排列

我正在努力将插入符号移动到DataGridView中的文本框编辑控件中 ,一行向上,一行向下,就像用户在按向上和向下箭头时得到的那样。

所以我的意思不是换行符之间的行,我的意思是文本框左右两边的行。

我不能使用GetCharIndexFromPosition和GetPositionFromCharIndex,因为并非所有文本都将始终显示在文本框显示区域中。

编辑:我无法模拟KeyPress,因为我正在处理DataGridView中的文本框单元格。 我的目标实际上是让箭头键在正常的文本框中执行它们的操作,而不是从一行跳到另一行。

这应该工作。

 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; 

我不认为这是最干净的解决方案。 也许您应该查看DataGridView属性/键处理。

GetPositionFromCharIndex()GetCharIndexFromPosition()有两个限制:

  1. 它们不适用于超出文本框边界的文本
  2. TextBox.SelectionStart的字符索引对于行尾的插入符和下一行开头的插入符号是相同的。

要纠正此问题,您可以:

  1. 在使用所述方法之前滚动文本框以显示相关行。
  2. 使用user32.dll中的GetCaretPos函数将其与SelectionStart的位置进行比较。 如果它们不相等,则意味着插入符号位于最后。
  3. 模拟{END}按键,将插入符号放在一行的末尾。

我遇到的另一个问题是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参考 。

  /// ------------------------------------------------------------------------------------ ///  /// Processes up key when a grid cell is in the edit mode. This overrides the default /// behavior in a grid cell when it's being edited so using the up arrow will move the /// IP up one line rather than moving to the previous row. ///  /// ------------------------------------------------------------------------------------ protected virtual bool ProcessUpKey(TextBox txtBox) { // Don't override the default behavior if all the text is selected or not multi-line. if (txtBox.SelectedText == txtBox.Text || !txtBox.Multiline) return false; int selectionPosition = txtBox.SelectionStart; // Getting the position after the very last character doesn't work. if (selectionPosition == txtBox.Text.Length && selectionPosition > 0) selectionPosition--; Point pt = txtBox.GetPositionFromCharIndex(selectionPosition); if (pt.Y == 0) return false; pt.Y -= TextRenderer.MeasureText("x", txtBox.Font).Height; txtBox.SelectionStart = txtBox.GetCharIndexFromPosition(pt); return true; } /// ------------------------------------------------------------------------------------ ///  /// Processes down key when a grid cell is in the edit mode. This overrides the default /// behavior in a grid cell when it's being edited so using the down arrow will move the /// IP down one line rather than moving to the next row. ///  /// ------------------------------------------------------------------------------------ protected virtual bool ProcessDownKey(TextBox txtBox) { // Don't override the default behavior if all the text is selected or not multi-line. if (txtBox.SelectedText == txtBox.Text || !txtBox.Multiline) return false; int chrIndex = txtBox.SelectionStart; Point pt = txtBox.GetPositionFromCharIndex(chrIndex); pt.Y += TextRenderer.MeasureText("x", txtBox.Font).Height; var proposedNewSelection = txtBox.GetCharIndexFromPosition(pt); if (proposedNewSelection <= chrIndex) return false; // Don't let "down" take you *up*. txtBox.SelectionStart = proposedNewSelection; return true; }