将插入符号移动到WPF文本框中的鼠标位置

时间:2017-06-13 11:24:50

标签: c# wpf mouseevent

我有一个子类文本框,只有当用户有意点击它时才会获得键盘焦点(插入符号)(它是复杂控件的一部分,用户可能并不总是想要这样的行为)。

因此,我必须在文本框中将此焦点放在代码中(使用Keyboard.Focus),因此我不能依赖现有行为来执行此操作。

问题是当用户点击(并且我调用Keyboard.Focus)时,未设置插入符号位置。这不是直观的,而且有点令人沮丧,需要用户进行第二次点击操作(一旦获得键盘焦点),将插入符号放在他们想要的正确位置。

使用GetCharacterIndexFromPoint,但它会给你错误的索引!如果你的鼠标超出了最后一个字符,它会在点击时将插入符号放在它之前,这在我看来可能比没有任何行为更令人恼火。

为此,我如何取出鼠标位置并从中获取合适的插入位置,以模仿控件的开箱即用行为(插入符号跳转到鼠标的最近有效位置) ?

我之前研究过这个并且空白了。

3 个答案:

答案 0 :(得分:0)

我找到了答案。

用户EriBeh的解决方案2 here,复制如下:

        SizeF size;
        using (Graphics graphics = Grapics.FromImage(new Bitmap(1, 1)))
        {
            size = graphics.MeasureString(CustomTextBox.Text, new Font(CustomTextBox.FontFamily.ToString(),     Convert.ToSingle(CustomTextBox.FontSize), System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel));
        }

        if (mousePoint.X >= size.Width) return CustomPasswordBox.Password.Length;
        else CustomTextBox.GetCharacterIndexFromPoint(mousePoint, true);

解决方案不太正确,因为它没有考虑任何填充或文本对齐。仅仅计算文本的宽度是不够的,还必须考虑文本在控件中的位置并相应地得出其最右边的点(相对于控件),然后可以测试鼠标是否更正确衍生价值。

因此,我已经适应了这一点(我的文本将始终以控件为中心):

        SizeF size;
        using (var graphics = Graphics.FromImage(new Bitmap(1, 1)))
        {
            size = graphics.MeasureString(Text, new Font(FontFamily.ToString(), Convert.ToSingle(FontSize), System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel));
        }
        var mousepos = Mouse.GetPosition(this);
        var textXLocationAtRightmostEdge = (ActualWidth / 2) + (size.Width / 2);
        CaretIndex = mousepos.X >= textXLocationAtRightmostEdge ? Text.Length : GetCharacterIndexFromPoint(mousepos, true);

卓越的解决方案赞赏。

答案 1 :(得分:0)

我遇到了类似的问题,当我的文本框也可以换行时,因此无法使用文本或文本框的宽度。所以我想出了(但尚未发现任何问题)

MouseDownStartPosition = e.GetPosition(textBox);

//check if user clicked some exact character
var characterIndexFalse = textBox.GetCharacterIndexFromPoint(MouseDownStartPosition, false);
//get nearest character to mouse
var characterIndex = textBox.GetCharacterIndexFromPoint(MouseDownStartPosition, true);

//GetCharacterIndexFromPoint often returns last but one character position when clicked right after textbox
//so check if characterIndexFalse is -1 (text not clicked) and if nearest character is last but one, assume that 
//user clicked behind string
if ((characterIndexFalse == -1) && (characterIndex + 1 == textBox.Text.Length)) {
   characterIndex++;
}

简要说明:

GetCharacterIndexFromPoint(true)返回最近的字符,该字符与字符串中的最后一个字符有问题,并选择了最后一个字符而不是一个。

GetCharacterIndexFromPoint(false)返回精确点击的字符;如果未单击任何字符,则返回-1。

因此,要解决这种情况,我检查是否没有单击确切的字符,并且最接近的字符是最后一个字符,但是我知道插入号必须放在最后一个字符之后。

答案 2 :(得分:0)

我可以在这里加2美分吗?

为什么WPF系统不能自己解决这个问题?

        // Get the protected OnMouseDown method via reflection.
        var textBoxBaseType = typeof(TextBoxBase);
        var onMouseDownMethod = textBoxBaseType.GetMethod("OnMouseDown", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

        System.Diagnostics.Debug.Assert(onMouseDownMethod != null);

        Point mousePoint = Mouse.GetPosition(txtBox);
        var mea = new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left);
        mea.RoutedEvent = e.RoutedEvent;    // Where e = the EventArgs parameter passed on to this method
        txtBox.SelectionLength = 0;
        onMouseDownMethod.Invoke(txtBox, new[] { mea });