通过避免文本框validation来关闭C#窗体

这是一个winform C#问题。 我有一个带有validation事件监听器的文本框,可以根据正则表达式validation文本框的内容。

validation后,如果输入的值不正确,我显示消息框,我正在取消该事件,以便鼠标光标移回到具有不正确值的文本框。

当我从该文本框移出到其他按钮/文本框时,这工作正常。

但是当我输入不正确的值并关闭表单(右上角的关闭按钮)时,它会validation文本框内容并抛出消息框,并且表单不会因为我正在处理事件而关闭。

问题是,当我单击表单右上角的X按钮时,我不希望激活validation因为我正在关闭表单。 我怎样才能做到这一点?

我会尽快发布代码段。

要使用validation处理程序(如下面的’txtIPAddress_Validating()’处理程序,同时能够关闭表单而不必输入有效条目,我执行以下操作:

1)启动validation处理程序:从要激活validation的控件的控件属性中,双击此控件事件列表中的“validation”事件。 通过单击此控件的属性表的事件(闪电看)工具栏按钮来访问控制事件列表。 然后,您可以在自动生成的处理程序中输入代码,其名称结合了控件的名称和“_Validating”。 这个处理程序中某些东西被建立为无效的部分可以通过添加’e.Cancel = true’指令来强制有效条目。

有关此类validation方法示例,请参阅下面的’txtIPAddress_Validating()’和’txtMaskBits_Validating()’代码。 不要被这些特定示例的完整validation机制分心。 您需要在自己的代码中查看和重现以强制validation,只需在您自己的validation方法的正确位置添加“e.Cancel = true”指令。 即,该值被识别为无效。

此时validation应该可以正常工作,但是任何关闭表单的尝试都会触发validation,该validation将在能够关闭表单之前停止并坚持有效值。 这并不总是你想要的。 如果不是这样,我继续以下。

2)’取消’按钮,也取消(禁用)所有validation:

a)在表单上放置一个常规的“取消”按钮,该按钮与下面的’btnCancel_Click()’方法相关联。

b)在常规’this.close();之前 指令,添加’AutoValidate = AutoValidate.Disable;’ 指令。 该指令禁用所有“validation”触发器。 请注意,在进行任何validation之前会触发’btnCancel_Click’事件。 对于将在validation事件后全部执行的表单关闭事件,情况并非如此。 这就是为什么不能从任何这些Form Closing事件中禁用validation的原因。

c)要使“取消”按钮正常工作,您还需要将此“取消”按钮的“CausesValidation”属性设置为“false”。 这是必要的,否则单击此按钮将触发validation,然后可通过上述’AutoValidate = AutoValidate.Disable;’禁用validation。 指令。

此时,您应该可以通过单击“取消”按钮退出,而无需先输入有效值。 但是,单击窗体窗口右上角的“X”按钮仍将强制进行validation。

3)使右上角的“X”按钮也取消validation:

这里的挑战是在执行validation之前捕获这样的“X”点击事件。 任何通过Form Closing处理程序执行此操作的尝试都不会起作用,因为一旦执行到达此类处理程序就太晚了。 但是,可以通过覆盖WndProc()方法并测试’m.Msg == 0x10’条件来立即捕获“X”按钮的单击。 当该条件为真时,先前引入的’AutoValidate = AutoValidate.Disable;’ 在这种情况下,指令也可以再次用于禁用整体validation。 请参阅下面的WndProc()方法以获取此类方法的代码示例。 您应该能够像在表单的类中一样复制和粘贴该方法。

此时,“取消”和“X”按钮都应该取消数值。 但是,可用于关闭表单的转义键不会。 当表单的’CancelButton’属性用于将此转义键链接到表单的“取消”按钮时,将激活此转义键。

4)使转义键也取消validation:

与“X”按钮类似,可以通过覆盖现有方法来捕获转义键。 这是ProcessDialogKey()方法。 再一次,之前介绍的’AutoValidate = AutoValidate.Disable;’ 指令也可用于禁用转义键的整体validation。 请参阅下面的代码中的’ProcessDialogKey()’重写方法,以了解如何完成此操作。 在这里,您应该能够复制并粘贴该方法,就像在您自己的表单类中一样。

此时你应该完成!

进一步考虑:

值得注意的是,关闭窗口的以下两种方法在这一点上也应该正常工作。 这两种方式是:

  • 左上方窗口图标按钮的“关闭”选项。
  • 按下Alt + F4,触发与上述“关闭”选项相同的关闭操作。

一旦引入上面第3点中描述的“X”按钮捕获机制,这两种关闭窗口的方法也开始取消validation。

到目前为止,这对我来说就是这样。 希望这有帮助!

我的代码示例如下:

public partial class frmMyIP : Form { public frmMyIP() { InitializeComponent(); } // To capture the Upper right "X" click protected override void WndProc(ref Message m) { if (m.Msg == 0x10) // The upper right "X" was clicked { AutoValidate = AutoValidate.Disable; //Deactivate all validations } base.WndProc(ref m); } // To capture the "Esc" key protected override bool ProcessDialogKey(Keys keyData) { if (keyData == Keys.Escape) { AutoValidate = AutoValidate.Disable; btnCancel.PerformClick(); return true; } return base.ProcessDialogKey(keyData); } public bool IsValidIP(string ipaddr) { string pattern = @"^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"+ @"(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$"; Regex check = new Regex(pattern); bool valid = false; if (ipaddr == "") { valid = false; } else { valid = check.IsMatch(ipaddr, 0); } return valid; } private void txtIPAddress_Validating(object sender, CancelEventArgs e) { string address = txtIPAddress.Text; if (!IsValidIP(address)) { MessageBox.Show("Invalid IP address!"); e.Cancel = true; } } private void cmbMaskBits_Validating(object sender, CancelEventArgs e) { int MaskBitsValue = Convert.ToInt32(cmbMaskBits.Text); if (MaskBitsValue<1 || MaskBitsValue>30) { MessageBox.Show("Please select a 'Mask Bits' value between 1 and 30!"); e.Cancel = true; } } private void btnCancel_Click(object sender, EventArgs e) { // Stop the validation of any controls so the form can close. // Note: The CausesValidation property of this  button // must also be set to false. AutoValidate = AutoValidate.Disable; this.Close(); } 
 private void Form1_FormClosing(object sender, FormClosingEventArgs e) { // Assume that X has been clicked and act accordingly. } 

创建一个结束事件,然后只需取消validation器。

在文本框的validation事件中插入以下内容作为第一行:

 //Allow the form to be closed if (this.ActiveControl.Equals(sender)) return; 

由于表单的close事件触发validation,并且因为这将(通常至少)是唯一会触发validation的表单事件,我们可以假设任何表单事件触发validation都是close事件。

尝试将CauseValidation设置为false

或者在此处查看: 如何在单击“表单”的“取消”按钮后跳过validation

或者尝试在formClosing事件中设置它

 private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e) { // CauseValidation to false or check } 

您需要的是一个类似于下面描述的实现,其中假设您有一个保存按钮和表单的取消按钮:

  public Form1() { // Disable validation in constructor textBox.CausesValidation = false; } private void OnSaveClicked(object sender, EventArgs e) { textBox.CausesValidation = true; if (ValidateChildren()) { // // Do saving of the form data or other processing here .... // Close(); } // // Set validation to false, as user may press Cancel next // textBox.CausesValidation = false; } private void OnCancelClicked(object sender, EventArgs e) { Close(); } 

与此处涉及黑客和额外多余代码以撤消某些内容的所有建议相比,实际答案非常简单。

“技巧”只是允许焦点改变而不是从表单本身的按钮激活validation。

您只需在表单上设置两个属性:

 MyForm.CausesValidation = false; MyForm.AutoValidate = AutoValidate.EnableAllowFocusChange; 

当您尝试关闭它时,表单会正常运行,并且validation仍然可以在其他输入之后工作,例如更改焦点或鼠标点击。

检查哪个按钮在validation检查中具有焦点。 如果取消按钮(在我的情况下是一个清除按钮),覆盖。 这是我从我的单元validation事件处理程序调用的内部方法。 (刚刚意识到这是一个C#问题,但你可以翻译)

 Private Sub validateCell(ByVal tagDesc As String, ByVal userInput As String, ByVal legalRegex As String, ByVal regexDesc As String, ByVal e As DataGridViewCellValidatingEventArgs) Dim match As Match = Regex.Match(userInput, legalRegex) Dim matches = match.Groups() Dim val = match.Value If val.Length = 0 Or userInput.Length > val.Length Then tagGrid.Rows(e.RowIndex).ErrorText = _ tagDesc & " must match pattern: " & regexDesc If Me.Cancel_Button.Focused Or Me.clearButton.Focused Then e.Cancel = False tagGrid.Rows(e.RowIndex).ErrorText = "" Else e.Cancel = True MsgBox(tagDesc & " must match pattern: " & regexDesc, MsgBoxStyle.Critical) End If Else e.Cancel = False tagGrid.Rows(e.RowIndex).ErrorText = "" End If End Sub 

我来到这里寻找一种简单的方法,当Validating事件处理程序引发exception,报告它并需要强制关闭表单时,使表单关闭。 在阅读了这个主题和其他许多内容之后,接下来的一个下午的实验,我已经做了几个发现,并开发了一个简单的黑客来迫使表格关闭。

首先是第一件事; 我发现当Validating事件调用this.Close()时 ,传递到其From_Closing事件过程的FormClosingEventArgs.Cancel标志被设置为TRUE ,从而有效地导致事件自行取消。 相反,正常的Close事件接收FormClosingEventArgs.Cancel标志设置为FALSE

由于表单上的Close方法不带参数,因此没有直接的方法可以强制解决问题,因此需要进行黑客攻击。 本文讨论了一些这样的黑客攻击,但我认为我的实现起来要简单得多。

黑客从一个简单的表单级布尔变量开始。

  bool _fExceptionIsFatal = false; 

除了定义Form_Closing事件处理程序之外,这是表单所需的唯一结构更改。

Form_Closing事件很简单。

  private void From1_Closing ( object sender , FormClosingEventArgs e ) { if (this.CausesValidation ) { // There is no sense repeating this procedure if another routine already did it. DisableValidation ( ); } // if (this.CausesValidation ) if ( _fExceptionIsFatal ) { // Cancel False == Allow form to close. e.Cancel = false; } // if ( _fExceptionIsFatal ) } // From1_Closing 

虽然DisableValidation是作为当前表单的本地方法实现的,但是通过将Form引用传递给库例程可以实现相同的function,因为Form是一个Form,其Controls集合是一个Controls集合,句点。 不久之后,我会这样做,同时实现其反转,再次启用validation。

  private void DisableValidation ( ) { foreach ( Control ctrl in this.Controls ) { ctrl.CausesValidation = false; } // foreach ( Control ctrl in this.Controls ) this.CausesValidation = false; } // DisableValidation 

第四部分解决方案同样简单明了; 只要您想强制关闭表单,在调用之前将_intValueAsInteger设置为TRUE关闭

将以下代码添加到表单中。 即使子控件正在validation,您也可以关闭表单。

 protected override void WndProc(ref Message m) { if (m.Msg == 0x10) // The upper right "X" was clicked { this.ActiveControl = null; this.AutoValidate = AutoValidate.Disable; } base.WndProc(ref m); }