WinFormsvalidation事件阻止Escape键关闭表单

我有一个带有单个TextBox的简单表单,以及OK和Cancel按钮。 Form的AcceptButton和CancelButton设置正确,OK和Cancel按钮的DialogResult设置为’OK’和’Cancel’。

我想在TextBox中添加validation,这将阻止用户在validation失败时对表单进行确认,但这也将允许它们像往常一样取消。

默认情况下,在所有控件上,CausesValidation属性为True,但我在取消按钮上将其更改为False。

果然,单击“确定”或按Enter键将运行我连接到TextBox的validation事件。 按取消按钮绕过validation,这是完美的。

但是,按Escape取消表单与按取消按钮的操作不同 – 它会引发Validating事件并阻止用户退出。

是否有任何方法可以使Escape键按预期执行,即不会引发Validating事件,就像按下Cancel按钮一样?

一个完整的解决方案是:

创建一个新的Windows窗体应用程序。 将第二个表单添加到项目中。

在InitializeComponent()之后将此代码粘贴到Form1的构造函数中:

MessageBox.Show((new Form2()).ShowDialog().ToString()); 

这显示了从我们的第二个表单传回的DialogResult。

在InitializeComponent()之后将此代码粘贴到Form2的构造函数中:

 TextBox txtName = new TextBox(); txtName.Validating += new CancelEventHandler((sender, e) => { if (txtName.Text.Length == 3) { MessageBox.Show("Validation failed."); e.Cancel = true; } }); Button btnOk = new Button { Text = "OK", DialogResult = DialogResult.OK }; Button btnCancel = new Button { Text = "Cancel", CausesValidation = false, DialogResult = DialogResult.Cancel }; FlowLayoutPanel panel = new FlowLayoutPanel(); panel.Controls.AddRange(new Control[] { txtName, btnOk, btnCancel }); this.AcceptButton = btnOk; this.CancelButton = btnCancel; this.Controls.Add(panel); 

在这个简化的示例中,如果输入了3个字符,则文本框将不允许您继续。 即使有3个字符,您也可以直接按取消按钮或关闭表格; 但是按下Escape键会这样做 – 它会触发Validating事件,而它应该像按下Cancel一样。

是的,这是ValidateChildren方法的一个尴尬的怪癖。 它不知道取消是有意的。 粘贴此代码以解决问题:

  protected override void OnFormClosing(FormClosingEventArgs e) { base.OnFormClosing(e); e.Cancel = false; } 

为避免运行导致副作用的Validate事件处理程序(如消息框),请将此语句添加到方法的顶部:

  private void txtName_Validating(object sender, CancelEventArgs e) { if (this.DialogResult != DialogResult.None) return; // etc.. } 

将此代码粘贴到表单中以在尝试validation表单之前设置DialogResult:

  protected override bool ProcessDialogKey(Keys keyData) { if (keyData == Keys.Escape) this.DialogResult = DialogResult.Cancel; return base.ProcessDialogKey(keyData); } 

我刚看到这个问题,因为我正在寻找相同的解决方案,并且ProcessdialogKey的覆盖是MS批准的解决方案,直到他们修复了错误(Escape应该像点击取消一样)。 此处也可以找到对此错误的讨论(仅使用Visual Basic而不是C#。错误已超过5年,显然仍未修复): 错误还是function? CancelButton vs Escape Key我试图找出C ++解决方案。

编辑添加:来自C#链接的解决方案:

 protected override bool ProcessDialogKey(Keys keyData) { if (keyData == Keys.Escape) { this.AutoValidate = AutoValidate.Disable; cancelButton.PerformClick(); this.AutoValidate = AutoValidate.Inherit; return true; } return base.ProcessDialogKey(keyData); } 

实际上,这会导致新的问题,因为它拦截了其他控件应该使用的转义,例如,如果你有一个combobox掉落,按下escape应该关闭combobox并且不退出对话框,上面的代码将会这样做。

可以在转义键事件上免除某些控件类型,但这不是一个好的解决方案,只是时间问题,直到另一个在内部使用转义的控件被引入到表单中,例如应该退出编辑模式的扩展控件逃跑

IMO非常迟钝,他们在逃跑时运行validation。 有谁知道背后的想法是什么,因为它不是一个错误…但它是一个错误。

如果该代码调用base.ProcessDialogKey(keyData)而不是cancelButton.PerformClick,那么您将更接近解决方案,因为由其他人决定如何处理转义键。 但是在这里将AutoValidate设置为Disabled然后将其恢复为原始值并不会阻止validation,因为它可能只是简单地发布事件并在队列中放置消息,直到它被设置回之后才使用该值它的原始价值。

通过将其设置为Disabled并且不将其返回到原始值,它将起作用,但是如果转义键然后被例如上面提到的丢弃的combobox拦截,那么你突然在OK上也禁用了validation。

德勤!

任何人都有关于如何使其工作的任何其他明智的想法,而不必指定所有可能的控件,以及他们需要逃脱时的条件是什么,例如控制是ComboBox并检查它是否被丢弃,如果是这样的话。

ProcessDialogKeys和Validating处理程序的答案都不适用于我,也许是因为我使用的是errorProvider而不是MessageBox。 我得到的最简单的答案是忘记validation,只需使用以下内容: –

 buttonOk.Click += (_,__) => { if(txtName.Text.Length == 3) { errorProvider1.SetError(txtName, "Wrong Length!"); DialogResult = DialogResult.None; } else { errorProvider1.SetError(txtName, string.Empty); } };