简体   繁体   English

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

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

Here is my code:这是我的代码:

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

This code works as it's supposed to:此代码按预期工作:

  1. if I insert a new unique character (a character that is not in the string textBox.Text) at the end of the textBox.Text如果我在 textBox.Text 的末尾插入一个新的唯一字符(不在字符串 textBox.Text 中的字符)
  2. if I try to insert the character that is in the string textBox.Text at the end of the textBox.Text如果我尝试在 textBox.Text 末尾插入字符串 textBox.Text 中的字符
  3. if I insert a new unique character in the middle of the string textBox.Text如果我在字符串 textBox.Text 的中间插入一个新的唯一字符

But this code does not work correctly when I try to insert a character (that is in the string textBox.Text) in the middle of a string textBox.Text.但是,当我尝试在字符串 textBox.Text 的中间插入一个字符(即在字符串 textBox.Text 中)时,此代码无法正常工作。 The selection cursor moves to the right, although it shouldn't, because the text doesn't change.选择 cursor 向右移动,尽管它不应该向右移动,因为文本没有改变。

Give this a shot:试一试:

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);
    }

Basically it checks if the length was modified from the original entered text(before the extra character(s) were removed).基本上它检查长度是否从原始输入的文本中修改(在删除额外字符之前)。 If it was, it moves the cursor to compensate for any characters removed.如果是,它会移动 cursor 以补偿删除的任何字符。

The TextChanged event cannot suppress the move of the caret to the right. TextChanged 事件无法抑制插入符号向右移动。 It is its default behavior.这是它的默认行为。 But you can compensate adding one line of code inside the TextChanged event and modifying the selectionStart value但是您可以补偿在 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);
}

The key line calculates if we need to compensate for the right move of the caret first grouping the characters in the textbox and then counting if any group has a count bigger than 1. If this is the case the selectionStart variable is adjusted to compensate.关键行计算我们是否需要补偿插入符号的右移,首先对文本框中的字符进行分组,然后计算任何组的计数是否大于 1。如果是这种情况,则调整 selectionStart 变量以进行补偿。

As you have discovered this approach fails short in keeping the characters in their original position.正如您所发现的,这种方法无法将字符保留在其原始 position 中。 If you try to insert an existing character before one already present the code above keeps the first one and removes the last one.如果您尝试在已经存在的字符之前插入现有字符,则上面的代码会保留第一个字符并删除最后一个字符。

If you want to keep the last one then you should use the KeyDown event or the KeyPress.如果要保留最后一个,则应使用 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 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);
    }
}

Of course you need to add an instance of MyTextBox to your forms instead of the standard TextBox.当然,您需要将 MyTextBox 的实例添加到 forms 而不是标准的 TextBox。

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

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