我有一个子类文本框,只有当用户有意点击它时才会获得键盘焦点(插入符号)(它是复杂控件的一部分,用户可能并不总是想要这样的行为)。
因此,我必须在文本框中将此焦点放在代码中(使用Keyboard.Focus),因此我不能依赖现有行为来执行此操作。
问题是当用户点击(并且我调用Keyboard.Focus)时,未设置插入符号位置。这不是直观的,而且有点令人沮丧,需要用户进行第二次点击操作(一旦获得键盘焦点),将插入符号放在他们想要的正确位置。
我会使用GetCharacterIndexFromPoint,但它会给你错误的索引!如果你的鼠标超出了最后一个字符,它会在点击时将插入符号放在它之前,这在我看来可能比没有任何行为更令人恼火。
为此,我如何取出鼠标位置并从中获取合适的插入位置,以模仿控件的开箱即用行为(插入符号跳转到鼠标的最近有效位置) ?
我之前研究过这个并且空白了。
答案 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 });