在 KeyUp 事件中检测按键

4

我有一个表单上的文本框,我想检测用户键入的键。这个文本框是多行的,并启用了自动换行。我不希望用户按回车键(因为我想在一行上输入所有文本,然后自动换行),所以我使用了下面的代码:

private void txtPlain_KeyPress(object sender, KeyPressEventArgs e) {
    if (e.KeyChar == (char)13) {
        MessageBox.Show("Enter keys are not allowed");
        e.KeyChar = (char)0;
    }
}

这在我的测试中运行良好,但当我测试CTRL+ENTER时,它无法正常工作,因为我不知道如何检测控制键。通过我的谷歌搜索,我发现需要使用KeyUp/Down事件,所以现在我有了以下代码:

private void txtPlain_KeyUp(object sender, KeyEventArgs e) {
    //if (e.KeyData == (Keys.Control | Keys.Enter)) {

    if (e.KeyCode == Keys.Enter || (e.KeyCode == Keys.Enter && e.Control)) {            
        MessageBox.Show("Enter keys are not allowed:");
        //e.KeyValue = Keys.None;
    }
}

第一行被注释掉的代码由于某些原因无法工作,如果有人能解释一下为什么会有用,那就太好了。
KeyUp/Down事件的问题在于我不知道如何从文本中删除回车键,与KeyPress事件不同,后者可以将KeyChar设置为零。该事件捕获Enter和Ctrl+Enter键,但光标仍然会移到TextBox的下一行。
感谢任何对此的帮助。

如果这是一个WinForm,那么执行类似这样的keypress检测就可以了...但如果这是一个WebForm,那么将keypress事件发送回服务器是一个不好的主意(因为它会创建一个chatty)。如果这是一个WebForm,请尝试使用类似jQuery的东西来检测keypress事件。 - Prisoner ZERO
@Prisoner:嗯,Keys 枚举是在 System.Windows.Forms 命名空间中定义的。这很不可能是一个 Web Forms 应用程序。 - Cody Gray
@Cody 谢谢……我甚至没有想到查找命名空间。 - Prisoner ZERO
3个回答

5

嗯,没有理由通过处理 KeyDownKeyUp 事件来禁止 Enter 键。您可以简单地将文本框控件的 AcceptsReturn 属性 设置为 False。这将防止多行文本框响应按下 Enter 键。

当然,这并不能解决 Ctrl+Enter 的问题。实际上,这是在 AcceptsReturn 属性设置为 False 时创建新行的预期方式。要解决这个问题,您需要处理其中一个键盘事件并防止控件接收此输入。

KeyDown 是一个很好的起点。你需要过滤掉包含 Keys.Enter 标志的任何键盘事件,这将捕获它们,无论它们与哪个其他修饰键组合。然后,一旦找到 Enter 键按下,你需要设置 e.Handled 属性为 True,以防止它被传递给控件。

不幸的是,我们还没有完成。文本框控件试图在内部处理某些按键,您将无法在按键事件处理程序方法中覆盖它。您还需要告诉控件不要将特定按键解释为输入键。有两种主要方法可以做到这一点。第一种(也是推荐的方法)是从基础TextBox类继承创建自己的自定义控件,然后覆盖受保护的IsInputKey方法。第二种(稍微简单一些)的方法只是处理PreviewKeyDown事件,并将IsInputKey属性设置为False。
示例代码:
private void txtPlain_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
    // Check if the KeyCode value has the Keys.Enter flag set
    if ((e.KeyCode & Keys.Enter) == Keys.Enter)
    {
        // Set the IsInputKey property to False
        e.IsInputKey = false;
    }
}

private void txtPlain_KeyDown(object sender, KeyEventArgs e)
{
    // Check if the KeyCode value has the Keys.Enter flag set
    if ((e.KeyCode & Keys.Enter) == Keys.Enter)
    {            
        // Show the user a message
        MessageBox.Show("Enter keys are not allowed in this textbox.");

        // Prevent the key event from being passed on to the control
        e.Handled = true;
    }
}

虽然我认为这只是为了测试目的,但你绝对需要在生产代码中删除那个MessageBox调用。找到另一种方式来提醒用户他们的输入不被允许,例如发出短暂的蜂鸣声并在文本框旁边放置ErrorProvider组件。显示消息框非常突兀,而且不太友好。请参见我的答案获取其他提示和技巧。


感谢以上内容...有几件事情需要注意:1-“AcceptsReturn”已设置为false(默认),但回车键仍然会将光标移到下一行-很奇怪!2-我在KeyDown事件中添加了上面的代码,消息框弹出,但即使按Ctrl,回车键仍会添加到文本框中。3-是的,消息框只是用于测试,所以将被删除。谢谢。 - Harag
我刚刚看到了编辑后的帖子,其中包含PreviewKeyDown事件,创建了一个新的Windows应用程序,所以只有一个带有一个文本框的表单 - 将多行设置为false(接受返回和自动换行为默认)。添加了上述代码 - 但仍然没有反应 - 消息框显示出来,因此它捕获了Enter键。 - Harag
@harag:嗯,消息框应该在按下回车键时显示。我是否对你想要实现的目标有所误解? - Cody Gray
@Cody Gray - 是的,它应该显示出来 - 但只是在我测试时。现在条件已经生效了,消息框将被移除。- 正如您所说,提醒用户的另一种方法更好。 - Harag
@harag:那就把那行代码删掉。我不确定问题出在哪里。 - Cody Gray
@Cody Gray - 消息行已被删除,但上面的代码仍然无法正常工作。回车键仍然会添加到文本框中。Gabriel编辑的代码似乎可以使用keypress和down事件。 - Harag

1
private void txtPlain_KeyUp(object sender, KeyEventArgs e) {
    //if (e.KeyData == (Keys.Control | Keys.Enter)) {

    if (e.KeyCode == Keys.Enter || (e.KeyCode == Keys.Enter && e.Control)) {            
        MessageBox.Show("Enter keys are not allowed:");
        //e.KeyValue = Keys.None;
        // mark event as handled
        e.Handled = true;
    }
} 

来自 MSDN链接

编辑:

我认为你需要按键按下事件而不是按键松开事件

编辑2:
这里有一些经过测试的代码,它可以按照你的要求工作:

        bool invalid=false;
        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.KeyCode & Keys.Enter) == Keys.Enter)
            {
                invalid = true;
            }
        }

        private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (invalid)
            {
                e.Handled = true;
            }
            invalid = false;
        }

我已经在KeyUp和KeyDown中尝试了e.Handled,但是没有任何反应。感谢MSDN链接 - 但是看起来它使用了KeyDown事件和Keypress事件。这可能是我在这种情况下需要做的。 - Harag
你完全没有必要同时处理 KeyDownKeyPress。MSDN 的示例很愚蠢。 - Cody Gray
@harag 希望它对你有用。我已经使用了 e.Handle = true; 并且事件没有进一步发送。 - Gabriel
@Cody 我不知道为什么。我会在 MSND 论坛上问,也许他们可以告诉我。 - Gabriel
@harag同样来自msdn:如果此属性的值为false,则用户必须按CTRL+ENTER才能在多行TextBox控件中创建新行。如果表单没有默认按钮,则ENTER键将始终在控件中创建新的文本行,而不管此属性的值如何。 - Gabriel
显示剩余4条评论

0

第一行被注释掉的代码由于某些原因无法工作,如果有人能解释为什么这很有用。

您想要检测Ctrl + Enter。 if (e.KeyData == (Keys.Control | Keys.Enter)) {..

Keys.Control和Key.Enter只是一些值请参考。现在进行逻辑或操作不一定会导致按下的键。完全不合逻辑的子句。

好的,现在来到您实际的问题,您想要检测Enter键和Ctrl + Enter键并将其视为相同。 此外,您想要撤消引入的换行符。尝试使用

PreviewKeyDown或Preview key up事件处理程序,并使用以下条件

if(e.KeyCode==Keys.Enter)

如果这个能用就告诉我


你完全误解了问题和代码片段。那不是逻辑或,而是按位或,并且在这里绝对是正确的做法。即使你链接的文档也说Keys枚举具有FlagsAttribute,表明它允许将其值按位组合。 - Cody Gray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接