Murach's "core" book on programming, Visual Basic 2010 (Read the About Visual Basic review here.) contains a section about how to validate data. Naturally, part of the text covers the Validating event that is available for many controls. The text contains this claim on page 222:
"... if one of the (Validating) tests fails, the Cancel property of the e parameter is set to True, which cancels all of the events that would normally follow the Validating event. This returns the focus to the TextBox so the user can fix the data."
"Although this technique works OK for some applications, it has a couple of weaknesses. ... once the user starts entering data into the control, there's no way to cancel the entry without entering valid data. If, for example, the user decides to exit from the application, he can't do that without finishing the entry for the control."
"I didn't know that!", sez I.
So I quickly worked up an example and Murach (actually, Anne Boehm, the author) was right. See the illustration:
Click Here to display the illustration
Some experimentation showed why. Single-stepping through the code showed that selecting any other object simply restarted the Validating event code again. I added Button, other TextBox controls, and a few odd things to see if I could gain control in any other code block before the Validating event code started again. No luck! But, as it turns out, I just didn't look hard enough. The answer is at the end.
But I did finally find a way! I'm not sure it's the best way, but it works. So here's the challenge:
Given this code (and a Windows Form project with TextBox1 and Button1 controls added) ...
Public Class Form1 ' You can add code here Private Sub Button1_Click( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles Button1.Click ' You can add any code in this Sub End Sub Private Sub TextBox1_Validating( ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs ) Handles TextBox1.Validating ' You can add any code in this Sub e.Cancel = True ' One rule: This must be executed normally to ' initiate validation on TextBox1 End Sub ' You can add your own procedures End Class ' You can even add your own Class if you like
... write the code that will allow Button1 to cancel the validation so the Form can be exited normally.
My Solution: Add the same TextBox1.Validating event handler to both Button1 and TextBox1. When you do that, both the Button Validating event and the TextBox Validating event are called, which gives you the opportunity to change e.Cancel back to False in the Button1 handler.
I was thinking that most people wouldn’t remember that you could have two different subroutines as a handler for the same event.
About Visual Basic reader Larry rained on my parade, however. He pointed out that there was a property "CausesValidation" that could be set for the Button that would avoid the whole problem. (Hey! Murach missed it too!)
After some consideration, I decided to leave this Quick Tip in place, both to give Larry credit and to demonstrate a general principal:
There is a property, method, or event for anything you need to do in .NET. If you can't find it, you just haven't looked hard enough yet.