为什么 GetCharIndexFromPosition() 对于文本框的最后一个字符没有正确 return?

Why the GetCharIndexFromPosition() doesn't return properly for last character of textbox?

public partial class Form1 : Form
{
    TextBox textBox;
    public Form1()
    {
        InitializeComponent();
        textBox = new TextBox() { Height = 30, Width = 200, Text = "Syncfusion Software", Font = new Font("Arial", 11) };
        textBox.MouseMove += textBox_MouseMove;
        this.Controls.Add(textBox);

    }

    void textBox_MouseMove(object sender, MouseEventArgs e)
    {
        var selectionStart = textBox.GetCharIndexFromPosition(e.Location);
        textBox.SelectionStart = selectionStart;
        textBox.SelectionLength = 0;
    }
}

这是我的代码,这是一个简单的示例,我试图获得有关 TextBoxGetCharIndexFromPosition() 方法的清晰信息。

在鼠标移动中,我使用文本框的当前鼠标位置获取字符索引位置,并根据它设置文本框的选择开始。因此,如果我移动鼠标,则将根据鼠标移动设置选择开始或插入位置。但是当鼠标移动到文本末尾时出现问题,选择开始未设置为最后。它设置在最后但之前。

例如,如果一个文本框包含文本 "stack",那么如果鼠标位置在 "k" 之后,那么插入符号位置应该在末尾,但它显示在 "c" 之间和 "k"。 GetCharIndexPosition() 没有 returns 最后一个字符的正确值。让我知道解决方案

提前致谢。

此致,

文卡特桑

这是已知的记录行为。 GetCharIndexFromPosition 方法 documentation备注 部分包含以下 重要 注意事项:

If the specified location is not within the client rectangle of the control, or is beyond the last character in the control, the return value is the index of the last character.

解决方法是使用反向方法GetPositionFromCharIndex调整返回的索引。

像这样

void textBox_MouseMove(object sender, MouseEventArgs e)
{
    var charIndex = textBox.GetCharIndexFromPosition(e.Location);
    var charPosition = textBox.GetPositionFromCharIndex(charIndex);
    if (e.Location.X > charPosition.X) charIndex++;
    textBox.Select(charIndex, 0);
}

P.S. 作为旁注,我不知道这种方法试图实现什么,但可以肯定的是它阻止了通过鼠标行为进行的标准文本选择.

这最终让我很困扰,所以我将 Ivan Stoev 的想法扩展为一种相当过度设计的方法,该方法计算最后一个字符的像素宽度并将其除以二以准确模拟与其他字符相同的行为。

该方法是为 drag/drop 场景编写的,其中将鼠标悬停在上方时将选择调整到放置位置。

// Cached, so it doesn't get recalculated on each moved pixel.
private Char _textBoxLastChar = '[=10=]';
private Int32 _textBoxLastCharHalfWidth = 0;

private void TextBox_DragOver(object sender, DragEventArgs e)
{
    if (!e.Data.GetDataPresent(DataFormats.UnicodeText))
        return;
    TextBox tb = sender as TextBox;
    if (tb == null)
        return;
    Int32 textLen = tb.Text.Length;
    if (textLen > 0 && _textBoxLastChar != tb.Text[textLen - 1])
    {
        _textBoxLastChar = tb.Text[textLen - 1];
        _textBoxLastCharHalfWidth = (Int32)Math.Round(GetStringWidth(_textBoxLastChar.ToString(), tb.Font) / 2);
    }
    Point localPoint = tb.PointToClient(new Point(e.X, e.Y));
    Int32 index = tb.GetCharIndexFromPosition(localPoint);
    // fix for fact it returns the last char position when you go outside text bounds.
    Int32 charPosition = tb.GetPositionFromCharIndex(index).X;
    if (textLen != 0 && index == textLen - 1 && localPoint.X > charPosition + _textBoxLastCharHalfWidth)
        index++;
    if (!tb.Focused)
        tb.Focus();
    tb.SelectionStart = index;
    tb.SelectionLength = 0;
}

public static Double GetStringWidth(String text, Font f)
{
    //create a bmp / graphic to use MeasureString on
    Single areaSize = f.Size * 20;
    using (Bitmap b = new Bitmap(1, 1))
    using (Graphics g = Graphics.FromImage(b))
    {
        SizeF sizeOfString = g.MeasureString(text, f, new SizeF(areaSize, areaSize), StringFormat.GenericTypographic);
        return sizeOfString.Width;
    }
}

当然,如果您更改了文本框的字体或字体大小,则必须将 _textBoxLastChar 重置回 '[=12=]'