繁体   English   中英

如何在 TextChanged 之后设置 TextBox.SelectionStart?

[英]How to set TextBox.SelectionStart after TextChanged?

这是我的代码:

private void textBox_TextChanged(object sender, EventArgs e)
{
    int selectionStart = textBox.SelectionStart;
    textBox.Text = new string(textBox.Text.Distinct().ToArray());
    textBox.Select(selectionStart, 0);
}

此代码按预期工作:

  1. 如果我在 textBox.Text 的末尾插入一个新的唯一字符(不在字符串 textBox.Text 中的字符)
  2. 如果我尝试在 textBox.Text 末尾插入字符串 textBox.Text 中的字符
  3. 如果我在字符串 textBox.Text 的中间插入一个新的唯一字符

但是,当我尝试在字符串 textBox.Text 的中间插入一个字符(即在字符串 textBox.Text 中)时,此代码无法正常工作。 选择 cursor 向右移动,尽管它不应该向右移动,因为文本没有改变。

试一试:

private void textBox_TextChanged(object sender, EventArgs e)
    {
        int selectionStart = textBox.SelectionStart;
        int originalTextLength = textBox.Text.Length;
        textBox.Text = new string(textBox.Text.Distinct().ToArray());
        int lengthDif = originalTextLength - textBox.Text.Length;
        textBox.Select(selectionStart - lengthDif, 0);
    }

基本上它检查长度是否从原始输入的文本中修改(在删除额外字符之前)。 如果是,它会移动 cursor 以补偿删除的任何字符。

TextChanged 事件无法抑制插入符号向右移动。 这是它的默认行为。 但是您可以补偿在 TextChanged 事件中添加一行代码并修改 selectionStart 值

private void textBox_TextChanged(object sender, EventArgs e)
{
    int selectionStart = textBox.SelectionStart;
    int cnt = textBox.Text.GroupBy(t => t).Any(x => x.Count() > 1) ? -1 : 0;
    textBox.Text = new string(textBox.Text.Distinct().ToArray());
    textBox.Select(selectionStart + cnt, 0);
}

关键行计算我们是否需要补偿插入符号的右移,首先对文本框中的字符进行分组,然后计算任何组的计数是否大于 1。如果是这种情况,则调整 selectionStart 变量以进行补偿。

正如您所发现的,这种方法无法将字符保留在其原始 position 中。 如果您尝试在已经存在的字符之前插入现有字符,则上面的代码会保留第一个字符并删除最后一个字符。

如果要保留最后一个,则应使用 KeyDown 事件或 KeyPress。

private void textBox_KeyDown(object sender, KeyEventArgs e)
{
    char c = (char)e.KeyValue;
    e.SuppressKeyPress = textBox.Text.Contains(c);
}

And if you need to process also the Paste command then you should write your own TextBox class and override the WndProc method called by the Windows API when you press CTRL+V or select the Paste menu

public class MyTextBox : TextBox
{
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x302 && Clipboard.ContainsText())
        {
            var pasteText = Clipboard.GetText().ToArray();
            var currText = this.Text.ToArray();
            var newText = pasteText.Except(currText).ToArray();
            Clipboard.SetText(new string(newText));
        }
        base.WndProc(ref m);
    }
}

当然,您需要将 MyTextBox 的实例添加到 forms 而不是标准的 TextBox。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM