The only things we do validation-related are these:
1) Give you access to the CausesValidation properties of each of the buttons. By default Back, Cancel, and Help have CausesValidation set to false, while Next and Finish have it set to true.
2) We force a validation of the current page when a button is pressed only if the button's CausesValidation is set to true.
3) We default the WizardPage.CausesValidation property setting to false (since item #2 kicks in the validation upon button clicks).
So as you can see, we aren't doing anything tricky here with validation. After debugging this some more, I found a workaround.
If you make a control invalid and press the Next button, the Next button's click event won't fire. This is correct behavior since its CausesValidation is true. If you make a control invalid and press the Cancel button, the Cancel button's click event DOES fire. This is also correct behavior since its CausesValidation is false.
What happens is that the Cancel button click event handler calls this.Close and something in the Form's internal close code is kicking off the validation. Then Microsoft's code is raising the Form.Closing event with the Cancel property defaulting to true, whereas in .NET 1.x it was always false. So what you can do to handle this is change that Cancel property back to false and it will close like it should.
It seems like Microsoft added this as a "feature" probably to prevent you from closing a form if there is invalid data on it.