Winforms文本框 - 使用Ctrl-Backspace删除整个单词

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Winforms文本框 - 使用Ctrl-Backspace删除整个单词相关的知识,希望对你有一定的参考价值。

我有一个Winforms对话框,其中包含一个允许单行输入的TextBox。我想允许用户能够按Ctrl-Backspace删除整个单词。这不是开箱即用的TextBox的默认行为;我得到一个矩形字符,而不是删除单词。

我已经确认ShortcutsEnabled属性设置为True

我确实发现我可以使用RichTextBox而不是TextBox来获取我想要的行为。这个问题是RichTextBox的外观(特别是边框)与TextBox的外观不同,我不需要或不想要标记文本的能力。

所以我的问题是如何最好地处理这种情况?我错过了TextBox上的一些属性吗?或者最好使用RichTextBox,更新外观以使其一致,并禁用文本的标记?

如果没有更好的方法,我很乐意编写处理KeyDown和KeyPress事件明确的代码,但认为值得先检查一下。

答案

/ *更新:请看下面Damir的答案,它可能是一个更好的解决方案:) * /

我将Ctrl + Shift + Left和Backspace发送到TextBox来模拟Ctrl + Backspace。效果几乎相同,无需手动处理控件的文本。您可以使用以下代码实现它:

class TextBoxEx : TextBox
{
    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        if (keyData == (Keys.Control | Keys.Back))
        {
            SendKeys.SendWait("^+{LEFT}{BACKSPACE}");
            return true;
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }
}

您还可以修改app.config文件以强制SendKey类使用更新的发送键的方法:

<configuration>
  <appSettings>
    <add key="SendKeys" value="SendInput" />
  </appSettings>
</configuration>
另一答案

DWFgiangurgolo,感谢您提供的信息。下面是它的精致版本。请注意,它也考虑ComboBox,因为它与TextBox具有相同的问题。另请注意,仅当TextBoxComboBox的配置允许时,快捷方式才有效。

TextBoxEx:

public class TextBoxEx : TextBox
{
    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        // Attention:
        // Similar code exists in ComboBoxEx.ProcessCmdKey().
        // Changes here may have to be applied there too.

        if (ShortcutsEnabled)
        {
            if (keyData == (Keys.Control | Keys.Back))
            {
                if (!ReadOnly)
                {
                    if (SelectionStart > 0)
                    {
                        int i = (SelectionStart - 1);

                        // Potentially trim white space:
                        if (char.IsWhiteSpace(Text, i))
                            i = (StringEx.StartIndexOfSameCharacterClass(Text, i) - 1);

                        // Find previous marker:
                        if (i > 0)
                            i = StringEx.StartIndexOfSameCharacterClass(Text, i);
                        else
                            i = 0; // Limit i as it may become -1 on trimming above.

                        // Remove until previous marker or the beginning:
                        Text = Text.Remove(i, SelectionStart - i);
                        SelectionStart = i;
                        return (true);
                    }
                    else
                    {
                        return (true); // Ignore to prevent a white box being placed.
                    }
                }
            }
            else if (keyData == (Keys.Control | Keys.A))
            {
                if (!ReadOnly && Multiline)
                {
                    SelectAll();
                    return (true);
                }
            }
        }

        return (base.ProcessCmdKey(ref msg, keyData));
    }
}

ComboxBoxEx:

public class ComboBoxEx : ComboBox
{
    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        // Attention:
        // Similar code exists in TextBoxEx.ProcessCmdKey().
        // Changes here may have to be applied there too.

        if (keyData == (Keys.Control | Keys.Back))
        {
            if (DropDownStyle != ComboBoxStyle.DropDownList)
            {
                if (SelectionStart > 0)
                {
                    int i = (SelectionStart - 1);

                    // Potentially trim white space:
                    if (char.IsWhiteSpace(Text, i))
                        i = (StringEx.StartIndexOfSameCharacterClass(Text, i) - 1);

                    // Find previous marker:
                    if (i > 0)
                        i = StringEx.StartIndexOfSameCharacterClass(Text, i);
                    else
                        i = 0; // Limit i as it may become -1 on trimming above.

                    // Remove until previous marker or the beginning:
                    Text = Text.Remove(i, SelectionStart - i);
                    SelectionStart = i;
                    return (true);
                }
                else
                {
                    return (true); // Ignore to prevent a white box being placed.
                }
            }
        }

        return (base.ProcessCmdKey(ref msg, keyData));
    }
}

字符串辅助(例如静态类StringEx):

/// <summary>
/// Returns the start index of the same character class.
/// </summary>
/// <param name="str">The <see cref="string"/> object to process.</param>
/// <param name="startIndex">The search starting position.</param>
/// <returns>
/// The zero-based index position of the start of the same character class in the string.
/// </returns>
public static int StartIndexOfSameCharacterClass(string str, int startIndex)
{
    int i = startIndex;

    if (char.IsWhiteSpace(str, i)) // Includes 'IsSeparator' (Unicode space/line/paragraph
    {                              // separators) as well as 'IsControl' (<CR>, <LF>,...).
        for (/* i */; i >= 0; i--)
        {
            if (!char.IsWhiteSpace(str, i))
                return (i + 1);
        }
    }
    else if (char.IsPunctuation(str, i))
    {
        for (/* i */; i >= 0; i--)
        {
            if (!char.IsPunctuation(str, i))
                return (i + 1);
        }
    }
    else if (char.IsSymbol(str, i))
    {
        for (/* i */; i >= 0; i--)
        {
            if (!char.IsSymbol(str, i))
                return (i + 1);
        }
    }
    else
    {
        for (/* i */; i >= 0; i--)
        {
            if (char.IsWhiteSpace(str, i) || char.IsPunctuation(str, i) || char.IsSymbol(str, i))
                return (i + 1);
        }
    }

    return (0);
}
另一答案

我有这些方法的问题:

  • 替换.Text具有大文本的滚动问题。
  • 在textBox.KeyDown事件处理程序中执行SendKeys.SendWait(“^ + {LEFT} {BACKSPACE}”)对我来说根本不稳定。
  • 使用.Cut()更改剪贴板(否则可以正常工作)。

查看.NET参考源,.Cut()确实引出了以下解决方案:在TextBox中选择文本,然后使用WM_CLEAR清除它。似乎工作正常,它不发送人工按键事件。

class CtrlBackspaceSupport
{
    TextBox textBox;
    public CtrlBackspaceSupport(TextBox textBox)
    {
        this.textBox = textBox;
        textBox.KeyDown += new KeyEventHandler(textBox_KeyDown);
    }

    [DllImport("user32.dll", SetLastError = true)]
    static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
    const int WM_CLEAR = 0x0303;

    void textBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.Back)
        {   // Ctrl+Backspace -> remove till word border before cursor
            e.SuppressKeyPress = true;
            if (0 == textBox.SelectionLength && textBox.SelectionStart > 1)
            {   // nothing selected
                var text = textBox.Text;
                int indexOfSpace = text.LastIndexOf(' ', textBox.SelectionStart - 2);
                if (-1 != indexOfSpace)
                {   // found something
                    indexOfSpace++;
                    textBox.Select(indexOfSpace, textBox.SelectionStart - indexOfSpace);
                    SendMessage(new HandleRef(textBox, textBox.Handle).Handle, WM_CLEAR, 0, 0);
                }
            }
        }
    }
}
另一答案

老问题,但我偶然发现了一个不需要任何额外代码的答案。

启用文本框的自动完成功能,CTRL-Backspace应该按照您的意愿工作。

CTRL-Backspace删除插入符号左侧的整个单词似乎是自动完成处理程序的“流氓功能”。这就是启用自动完成功能修复此问题的原因。

Source 1 | Source 2

--

您可以通过将AutoCompleteModeAutoCompleteSource设置为您喜欢的任何内容来启用自动完成功能(例如,以上是关于Winforms文本框 - 使用Ctrl-Backspace删除整个单词的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 C# winforms 中一次将文本写入多个文本框?

如何在 C# Winforms 程序的文本框中突出显示文本?

所有者绘制文本框以在 WinForms 中使用

Winforms,我可以在这里使用文本框而不是组合框吗? (超过 15k 选项的下拉列表)

c++ Winforms文本框错误

在 C# winforms 应用程序中使用文本框过滤 Treeview