编程方式移动在文本框中插入符号,排队和线下(programmatically move caret

2019-09-18 07:16发布

我挣扎着一个DataGridView中移动在一个文本框编辑控件插入符号,一个排队一线下来,就像用户将按下上时和向下箭头得到。

所以,我的意思并不是作为行是什么换行符之间,我的意思是行作为什么是文本框的左侧和右侧之间。

我不能使用GetCharIndexFromPosition和GetPositionFromCharIndex因为不是所有的文本将始终在文本框中显示区显示。

编辑:我不能模拟按键响应,因为我处理的一个DataGridView中的文本框的细胞。 我的目标是实际上正在箭头键做自己会做一个正常的文本框的东西,而不是从行到行跳跃。

Answer 1:

这应该工作。

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属性/密钥处理。



Answer 2:

该方法GetPositionFromCharIndex()GetCharIndexFromPosition()有两个限制:

  1. 他们不超出文本框的边框文字工作
  2. 的字符索引TextBox.SelectionStart是用于在线路的端部的插入符号并在下一行的开头插入符是相同的。

为了解决这个问题,您可以:

  1. 滚动文本框使用方法说之前显示相关行。
  2. 使用GetCaretPos函数从user32.dll中把它与SelectionStart的位置进行比较。 如果它们不相等,这意味着插入符号是在一行的末尾。
  3. 模拟{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}");
                }
            }
        }
    }
}

信用的理念去这个答案 ,你可能还需要看看上GetCaretPos参考MSDN及其他插入符的功能 。



Answer 3:

    /// ------------------------------------------------------------------------------------
    /// <summary>
    /// 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.
    /// </summary>
    /// ------------------------------------------------------------------------------------
    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;
    }

    /// ------------------------------------------------------------------------------------
    /// <summary>
    /// 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.
    /// </summary>
    /// ------------------------------------------------------------------------------------
    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;
    }


文章来源: programmatically move caret in textbox, line up and line down