显示 MessageBox 取消 SupressKeyPress=true

Showing a MessageBox cancels SupressKeyPress=true

我有一个多行 TextBox 的表格。当用户想要创建一个新行时,他应该按 Shift+Enter,但是当他只按 Enter,什么都不应该发生。所以这是我的代码:

private void TextBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyData == (Keys.Shift | Keys.Enter))
    {
        int pos = textBox1.SelectionStart;
        textBox1.SelectedText = Environment.NewLine;
        textBox1.SelectionStart = pos + 2;
        e.Handled = e.SuppressKeyPress = true;
        return;
    }
    if (e.KeyCode == Keys.Enter)
    {
        e.SuppressKeyPress = true;
    }
}

这非常有效。

当用户只按Enter时,我想显示一个MessageBox,所以我添加了下面一行:

    ...
    if (e.KeyCode == Keys.Enter)
    {
        MessageBox.Show("Hello"); // <-- Here
        e.SuppressKeyPress = true;
    }

问题是现在显示 MessageBox 后,光标向下移动一行,这是我不想要的。

我该如何解决?我试图更改 MessageBox 和按键抑制之间的顺序,但它似乎不起作用。

您在 Keys.Enter-only 条件下使用 e.KeyCode 而不是 e.KeyDatae.KeyCode 在任何情况下都将设置为 Keys.Enter,无论是否按下 SHIFT

不需要将位置前进 2:当您插入一段新文本时,插入符号位置会自动更新。

请注意,设置 e.SuppressKeyPress = true; 也会设置 e.Handled = true;Net source code

注意:使用 RichTextBox,您不需要 BeginInvoke MessageBox 来丢失 Enter 按键. TextBox 控件具有 AcceptReturn 属性。当您关闭 MessageBox 时,密钥会传回。不管属性的值是多少。

private void TextBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyData == Keys.Enter)
    {
        e.SuppressKeyPress = true;
        BeginInvoke(new MethodInvoker(() => MessageBox.Show("Hello")));
    }

    if (e.KeyData == (Keys.Shift | Keys.Enter))
    {
        textBox1.SelectedText = "\r\n";
        e.SuppressKeyPress = true;
    }
}

我想问题是您正在从原始控件的处理程序创建另一个控件(MessageBox)。可能 重置 supresskeypress 标志。

编辑:原因更微妙,我从@Nouman 链接的链接答案中复制@Hans Passant 的评论:

MessageBox is dangerous when used in the wrong spot, same kind of danger as the infamous DoEvents(). It causes re-entrancy problems. It screws up your SuppressKeyPress request since that won't be done until after your event handler completes. Which won't happen until after the message box closes. Since MessageBox dispatches messages, it will dispatch the KeyPress as well so SuppressKeyPress has no effect whatsoever.

我能够在 Linux 框中重现该问题,使用 Mono 5.20.1 和 Xamarin 的 WinForms[=30 实现=].

用状态栏代替 MessageBox 怎么样?如果您可以更改它,那么下面的代码就可以解决问题。如果没有,按照链接的答案,您将找到 BeginInvoke().

形式的解决方案
public class MainWindowCtrl
{
    public MainWindowCtrl()
    {
        this.view = new MainWindowView();

        this.view.Editor.KeyDown += (sender, e) => this.OnEditorKeyDown( e );
        this.view.FormClosed += (sender, e) => Application.Exit();

        this.view.Show();
    }

    void OnEditorKeyDown(KeyEventArgs e)
    {
        this.view.StatusBar.Text = "Ready";

        if (e.KeyData == Keys.Enter)
        {
            this.view.StatusBar.Text = "Press Shift + Return!!";
            //MessageBox.Show( "Press Shift + Return!!" );
            e.SuppressKeyPress = true;
            return;
        }

        if (e.KeyData == (Keys.Shift | Keys.Enter))
        {
            int pos = this.view.Editor.SelectionStart;

            this.view.Editor.SelectedText = System.Environment.NewLine;
            this.view.Editor.SelectionStart = pos + 2;

            e.Handled = e.SuppressKeyPress = true;
            return;
        }
    }

    MainWindowView view;
}

希望对您有所帮助。

"Messagebox.show" 它会阻止 ui 和后续代码的更新,但不会阻止事件处理。

private void TextBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyData == (Keys.Shift | Keys.Enter))
    {
        int pos = textBox1.SelectionStart;
        textBox1.SelectedText = Environment.NewLine;
        textBox1.SelectionStart = pos + 2;
        e.Handled = e.SuppressKeyPress = true;
        return;
    }
    if (e.KeyCode == Keys.Enter)
    {
        MessageBox.Show("Hello");
        e.SuppressKeyPress = true;
    }
}

您在此代码中更改了 "e.SuppressKeyPress",但 window 上的事件已经处理了您的输入。

private bool test = false;

private void TextBox1_TextChanged(object sender, EventArgs e)
{
    if (test)
    {
        test = false;
        textBox1.Text += "Test";
    }
}

private void TextBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyData == (Keys.Shift | Keys.Enter))
    {
        int pos = textBox1.SelectionStart;
        textBox1.SelectedText = Environment.NewLine;
        textBox1.SelectionStart = pos + 2;
        e.Handled = e.SuppressKeyPress = true;
        return;
    }
    if (e.KeyCode == Keys.Enter)
    {
        test = true;
        MessageBox.Show("Hello");
        e.SuppressKeyPress = true;
        test = false;
    }
}

可以通过对应的代码查看

如果您键入 "Enter" "Test" 将添加到文本框

private void TextBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyData == (Keys.Shift | Keys.Enter))
    {
        int pos = textBox1.SelectionStart;
        textBox1.SelectedText = Environment.NewLine;
        textBox1.SelectionStart = pos + 2;
        e.Handled = e.SuppressKeyPress = true;
        return;
    }
    if (e.KeyCode == Keys.Enter)
    {
        this.BeginInvoke(new Action(() =>
        {
            MessageBox.Show("Hello");
        }));

        e.SuppressKeyPress = true;
    }
}

您可以使用 BeginInvoke

我为那些不想弄乱调用方法、手动启动新线程等的人找到了一些 'hack'

我的(旧)代码不起作用

private void textEditKeyPress(object sender, KeyEventArgs e)
        {
            if (e.KeyValue == 220)
            {
                e.SuppressKeyPress = true;                
                MessageBox.Show( @"\ not allowed. Use / instead.");

            }
        }

通过将代码更改为

private async void tEditDropBoxFolderName_EditValueChanged(object sender, KeyEventArgs e)
        {
            if (e.KeyValue == 220)
            {
                e.SuppressKeyPress = true;
                await Task.Delay(100);
                MessageBox.Show( @"\ not allowed. Use / instead.");

            }
        }

一切正常,我还没有发现任何副作用。