的WinForms文本框 - 使用CTRL-Backspace键删除整个词(Winforms Tex

2019-06-25 20:52发布

我有其他控件中包含一个文本框,允许输入的单行的WinForms对话框。 我想,让用户能够按Ctrl-Backspace键删除整个单词。 这是不是与外的现成文本框的默认行为; 我得到一个矩形的性格,而不是删除的字。

我已经证实了ShortcutsEnabled属性设置为True

我发现我可以用一个RichTextBox,而不是一个TextBox得到我想要的行为。 这里的问题是,RichTextBox的(境特别)的外观是从文本框的不同,我并不需要或想要的文字标记的能力。

所以我的问题是如何最好地处理这种情况? 有没有对我缺少的文本框的一些财产? 或者是它最好使用RichTextBox的,更新的外观,因此是一致的,而文字的禁用标记?

我比较高兴编写代码来处理KeyDown和按键事件明确地,如果没有更好的办法,但认为这是值得一试第一。

Answer 1:

/ *更新:也请看看下面达米尔的回答,它可能是一个更好的解决办法:) * /

我会通过发送按Ctrl + Shift +左键和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>


Answer 2:

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

对于文本框启用自动完成和CTRL-Backspace键应该工作,只要你想它。

CTRL-Backspace键删除整个单词插入符号左边似乎是自动完成处理的“ 流氓特色 ”。 这就是为什么能够自动完成修复此问题。

源1 | 源2

-

你能使用的设定自动完成功能AutoCompleteModeAutoCompleteSource你类似的东西(例如, SuggestRecentlyUsedList



Answer 3:

虽然给ProcessCmdKey重写工作不错,首先,它本身限制为Ctrl + Backspace键只有一个迭代,主要是因为使用SendWait模仿按键的,如果你按住Ctrl键的同时再次按Backspace键,系统似乎只认按下退格键。 如果你登录倍率的按键,你会发现,你从来没有真正按额外的键的集合。

另一种方法是明确地管理在给ProcessCmdKey重写文本框的外观,并且不发送多个键映射到系统中。 这很容易被应用到按Ctrl + Delete键也是如此。

我已经包含了一些常见的“停车点”为按Ctrl + Backspace键的行为,并使用switch语句,而不是一个正则表达式。 他们从来没有觉得不够干净,我通常会漏掉一个字

如果你看到我的代码的任何问题,通过各种手段,请让我知道。 好运的人仍然被这个难题糊涂!

public class TextBoxEx : TextBox
{
    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        if (keyData == (Keys.Back | Keys.Control))
        {
            for (int i = this.SelectionStart - 1; i > 0; i--)
            {
                switch (Text.Substring(i, 1))
                {    //set up any stopping points you want
                    case " ":
                    case ";":
                    case ",":
                    case "/":
                    case "\\":                        
                        Text = Text.Remove(i, SelectionStart - i);
                        SelectionStart = i;
                        return true;
                    case "\n":
                        Text = Text.Remove(i - 1, SelectionStart - i);
                        SelectionStart = i;
                        return true;
                }
            }
            Clear();        //in case you never hit a stopping point, the whole textbox goes blank
            return true;
        }
        else
        {
            return base.ProcessCmdKey(ref msg, keyData);
        }
    }  
}


Answer 4:

我不知道这是可能的,而不定制的KeyDown或按键事件,下面的代码工作,但:

private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
    if ((e.KeyCode == Keys.Back) && e.Control)
    {
        e.SuppressKeyPress = true;
        int selStart = textBox1.SelectionStart;
        while (selStart > 0 && textBox1.Text.Substring(selStart - 1, 1) == " ")
        {
            selStart--;
        }
        int prevSpacePos = -1;
        if (selStart != 0)
        {
            prevSpacePos = textBox1.Text.LastIndexOf(' ', selStart - 1);
        }
        textBox1.Select(prevSpacePos + 1, textBox1.SelectionStart - prevSpacePos - 1);
        textBox1.SelectedText = "";
    }
}


Answer 5:

这是我登陆上去使用,它同样可以处理多行文本框

private void HandleCtrlBackspace_KeyDown(object sender, KeyEventArgs e) {
  switch (e.KeyData) {
    case (Keys.Back | Keys.Control):
      e.SuppressKeyPress = true;
      TextBox textbox = (TextBox)sender;
      int i;
      if (textbox.SelectionStart.Equals(0)) {
        return;
      }
      int space = textbox.Text.LastIndexOf(' ', textbox.SelectionStart - 1);
      int line = textbox.Text.LastIndexOf("\r\n", textbox.SelectionStart - 1);
      if (space > line) {
        i = space;
      } else {
        i = line;
      }
      if (i > -1) {
        while (textbox.Text.Substring(i - 1, 1).Equals(' ')) {
          if (i.Equals(0)) {
            break;
          }
          i--;
        }
        textbox.Text = textbox.Text.Substring(0, i) + textbox.Text.Substring(textbox.SelectionStart);
        textbox.SelectionStart = i;
      } else if (i.Equals(-1)) {
        textbox.Text = textbox.Text.Substring(textbox.SelectionStart);
      }
      break;
  }
}


Answer 6:

这是溜溜的路要走:)

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    //if ctrl+bcksp
    if (e.KeyChar == 127)
    {
        //if not last word
        if (textBox1.Text.Split (' ').Count() > 1)
        {
            //remoce last word form list and put it back together (gotta love lambda)
            textBox1.Text = textBox1.Text.Split (' ').Take (textBox1.Text.Split (' ').Count() - 1).Aggregate ((a,b) => a + " " + b);
            //set selection at the end
            textBox1.SelectionStart = textBox1.Text.Length;
        }
        else if (textBox1.Text.Split (' ').Count() == 1)
        {
            textBox1.Text = "";
        }
    }
}


Answer 7:

这工作不错:

static Regex RegExWholeWord = new Regex(@"(\r\n|[^A-Za-z0-9_\r\n]+?|\w+?) *$", RegexOptions.Compiled);

在键下,使用

var m = RegExWholeWord.Match(textbox.Text, 0, textbox.SelectionStart);
if (m.Success)
{
    textbox.Text = textbox.Text.Remove(m.Index, m.Length);
    textbox.SelectionStart = m.Index;
}


Answer 8:

正则表达式为这个做。 用它。

    private void TextBox_KeyDown(object sender, KeyEventArgs e)
    {
        TextBox box = (TextBox)sender;
        if (e.KeyData == (Keys.Back | Keys.Control))
        {
            if (!box.ReadOnly && box.SelectionLength == 0)
            {
                RemoveWord(box);
            }
            e.SuppressKeyPress = true;
        }
    }

    private void RemoveWord(TextBox box)
    {
        string text = Regex.Replace(box.Text.Substring(0, box.SelectionStart), @"(^\W)?\w*\W*$", "");
        box.Text = text + box.Text.Substring(box.SelectionStart);
        box.SelectionStart = text.Length;
    }


Answer 9:

我回答在VB而不是C#因为我一直在寻找在VB此解决方案,但无法找到一个,但这些C#响应帮我做出来:-D

在模块中创建此子

Public Sub ctrl_bksp(ByRef t As TextBox)
    Dim ss As Integer = t.SelectionStart
    Dim sl As Integer = t.SelectionLength
    Dim tl As Integer = t.TextLength

    '//Split either side of selection start
    Dim strPre As String = Strings.Left(t.Text, tl - (tl - ss))
    Dim strPost As String = Strings.Right(t.Text, tl - ss - sl)

    '//Get Last Space Location in StrPre
    Dim s As Integer = Strings.InStrRev(RTrim(strPre), " ")

    strPre = Strings.Left(strPre, s)

    t.Text = strPre & strPost
    t.SelectionStart = s
End Sub

然后你可以从任何文本框的KeyPress事件中调用该子:

Private Sub Textbox1_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles Textbox1.KeyPress
    Select Case e.KeyChar
        Case Chr(127)   '//Ctrl+Backspace
            e.Handled = True
            Call ctrl_bksp(Textbox1)
    End Select
End Sub

这将工作无论身在何处的选择是字符串中,文字和是否被选中,并响应辉煌!



Answer 10:

DWF和giangurgolo ,感谢你提供的信息。 下面它的改良版本。 请注意,它也考虑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);
}


Answer 11:

我曾与这些方法的问题:

  • 更换。文本已滚动大文本的问题。
  • 这样做SendKeys.SendWait(“^ + {左} {}退格”)在textBox.KeyDown事件处理程序并不稳定,在为我所有。
  • 使用.Cut()改变剪贴板(但完全正常工作)。

纵观.NET参考源是什么.Cut()不会导致我到下面的解决方案:选择在文本框中的文字,然后用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);
                }
            }
        }
    }
}


文章来源: Winforms Textbox - Using Ctrl-Backspace to Delete Whole Word