I am looking for a simple solution to the following problem:
I am using a simple TextBox control with the Text property bound to a property in the code behind. Additionally I am using a validation rule to notify the user of malformed input.
… error display style here …
Now after entering valid data into the TextBox the user can hit a button to send the data. When clicking the button the data from the bound property UserName in the code behind is evaluated and sent.
The problem is that a user can enter valid data into the TextBox and this will be set in the property UserName. If the user then decides to change the text in the TextBox and the data becomes invalid, the setter of the property UserName is not called after the failed validation.
This means that the last valid data remains in the property UserName, while the TextBox display the invalid data with the error indicator. If the user then clicks on the button to send the data, the last valid data will be sent instead of the current TextBox content.
I know I could deactivate the button if the data is invalid and in fact I do, but the method is called in the setter of UserName. And if that is not called after a failed validation the button stays enabled.
So the question is: How do I enable calling of the property setter after a failed validation?
How I handle this in my view model classes:
It’s a little awkward to get this all set up at first, but once you’ve done it, you have a simple and straightforward way to report validation errors to the UI (via the
DataErrorValidationRule), a straightforward way to know whether any given property is valid or not (check_Errors), and anIsValidproperty that tells you whether or not the whole view model is valid. (Also, you can extend theIsValidproperty to handle the case where all the properties of the view model are valid but the view model itself is not, e.g. two mutually exclusive flags are both set.) And as long as you make theminternal, the validation methods can be unit tested via NUnit or whatever.I should add that the above code is off the top of my head and may or may not work as written – my actual working code is in a base class and has a lot of other things baked into it that would just be confusing.