Validation errors prevent the property setter being called - c#

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?

You could set the ValidationRule.ValidationStep property for your validation rules to ValidationStep.UpdatedValue. This first updates the source, and then performs validation. That means, your property setter should be called even though your validation fails. Note that this property is only available from .NET 3.5 SP1 upwards. For more details, see this blog post (paragraph "How do I use it? (Part 1)").

How I handle this in my view model classes:
public class MyViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private Dictionary<string, string> _Errors = new Dictionary<string, string>();
public object SomeProperty
{
get { return _SomeProperty; }
set
{
if (value != _SomeProperty && !ValidationError("SomeProperty", value))
_SomeProperty = value;
OnPropertyChanged("SomeProperty");
}
}
}
private bool ValidationError(string propertyName, object value)
{
// I usually have a Dictionary<string, Func<object, string>> that maps property
// names to validation functions; the functions return null if the property
// is valid and an error message if not. You can embed the validation logic
// in the property setters, of course, but breaking them out as separate methods
// eases testing.
_Errors[propertyName] = _ValidationMethods[propertyName](value);
OnPropertyChanged("IsValid");
}
public bool IsValid
{
get { return !(_Errors.Where(x => x.Value != null).Any()));
}
public string this[string propertyName]
{
get
{
return (_Errors.ContainsKey(propertyName))
? _Errors[propertyName]
: null;
}
}
}
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 an IsValid property that tells you whether or not the whole view model is valid. (Also, you can extend the IsValid property 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 them internal, 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.

Related

Initializing class member in UserControl

Class is derived from Control in Asp.Net C#.
Public class member is defined as:
public bool isPresent = true;
Then in Render method check is performed :
if (isPresent)
doSomething;
On a form this field is set to false:
<c:CustomControl id="CustomControl1" isPresent="false">
When this code is executed locally from VS, everything is fine. Being deployed to the server, however, throws exception for the line with check for "if (isPresent)", saying that object reference is not set.
At the same time, if this line is changed to be "if (isPresent == true)", everything is fine both locally and on the server.
Is setting of value for class member of the Control different when run from VS and from IIS? Is it initialized in IIS before comparison operation, and not before implicit check?
UPDATE: as has been correctly pointed, this variable is a field, not a property. There is no other class member (and no property with same name).
UPDATE2: in addition, if check for value being not null is added, there is no exception anymore. Can it be the case that object initializer sets value of the field in case of explicit comparison operation?
if (isPresent == null)
return;
if (isPresent)
doSomething;
When creating user controls, the most advisable manner to store property values is in the View State, as follows:
public bool IsPresent
{
get
{
bool isPresent = false;
if (ViewState["IsPresent"] != null)
{
isPresent = (bool) ViewState["IsPresent"];
}
return isPresent;
}
set
{
ViewState["IsPresent"] = value;
}
}
Then, the control would be declared as follows (Note that the IsPresent starts with Upper I):
<c:CustomControl id="CustomControl1" IsPresent="false">
Whenever storing data on controls, keep in mind that they must be persisted on the page. If you simply declare a variable, there is no guarantee that the data will hold between requests. The only manner to make sure the data is persisted, is to save it in the View State. You can find support to these statements here and here.
The question of why the behavior changes in the IIS and Visual Studio may be not relevant here because simply declaring a variable, as stated above, provides no assurance at all that the data will be saved.
Regarding the Property being a getter/setter, note that it must be declared as shown above, in order to the property to be recognized by the ASPX page.

Sanitising ASP.NET input (allowing angle brackets)

I have read about customising input validation for ASP.NET requests to avoid the dreaded "a potentially dangerous value was detected". I'm using the following code to allow angled brackets to pass validation.
public class RequestValidator : System.Web.Util.RequestValidator {
protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex) {
validationFailureIndex = 0;
switch (requestValidationSource) {
case RequestValidationSource.Form:
if (control is CustomTextBox) { // How can I get the control?
// allow angle brackets to pass validation
value = value.Replace("<", "<").Replace(">", ">");
}
break;
}
return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
}
}
Now that I'm allowing these potentially dangerous values through the validation filter I'd like to be sure that they're being properly handled. This is a Web Forms environment so I thought I'd create a CustomTextBox control, override the Text property and HtmlEncode the string.
As you can see from the comment in the code above, I'd like to restrict my RequestValidator so that it only allows 'dangerous' values to pass validation if I can be sure they're going to be handled by my CustomTextBox. How can I get a reference to the Control when all we have to go on is the value and the collectionKey?
The validation of the Form Keys happen even before the Page PreInit event. There are no controls created at that time.
I think your best chance would be holding to a collection of UniqueIDs of all CustomTextBox instances that exists on the page currently. Having that collection, you could check if the form key being validated exists on the collection, meaning that it is in fact a CustomTextBox.
This collection could be managed inside the CustomTextBox control and saved on the Session or Application Cache.
I would suggest to explicitly set ValidateRequestMode property to ValidateRequestMode.Disabled in your custom control constructor and override Text property (or whatever property or you are using to store value) getter and there return sanitized value based on your specific scenario.

Custom handling of invalid character inputs

Here's the scenario. I have a textbox on the UI which is bound to a double property. If a character, say a '#' is typed in the textbox, the WPF validation is not enough for the application. I need to display a custom message and also disable some controls from the code. (These controls to be disabled are not part of the xaml.) As of now, the only way I could think of to do this is to bind the textbox to a string property and use the TryParse method. However, this will be a huge inconvenience. Is there a way to get the notification that an invalid character has been entered, without having to change the property to the string type?
well i use the "string" solution in my viewmodel. works best with IDataErrorInfo and binding.
but sometimes i also use a InputMaskbehavior for my Textboxe. so the user can just input characters wich is defined for the inputmask.
If you are using the MVVM pattern then you probably should have a string property in your ViewModel as this is what is entered on a Textbox. Even when you need the double for your model you have a string on your view. Then you can do whatever validation you need on the string property. Something like:
public string TextProperty
{
get
{
return _textProperty;
}
set
{
if (_textProperty != value)
{
_doubleProperty = this.TransformAndValidateString(value);
_textProperty = value;
}
}
}
Regarding disabling controls when an error is present look here:
IDataErrorInfo

Binding not refresing when I set the variable in the setter

I have a text bound to a property as follows
The user is expected to type in a File Name. Sometimes however users may type in invalid characters. So my backing property in the View Model looks as shown below
private string outputFileName;
public string OutputFileName
{
get
{
return outputFileName;
}
set
{
string temp = value;
if (true == IsValidFileName(temp))// this function uses Path.Getinvalidfilechars
{
outputFileName = value;
}
else
{
MessageBox.Show(string.Format("{0} contains one or more invalid characters
for a file Name",temp));
}
base.OnPropertyChanged("OutputFileName");
}
}
Here is the problem, the text box still shows the invalid char. why is the OnPropertyChanged not causing the text in the text box to go back to the old value without the invalid char.
How can I get that behaviour
In the else statement, the backing field for OutputFileName is not being assigned a different value. If you want to revert back to the previous value, then save that in another variable and update the backing field in the else statement and then the property changed event will change the UI with the old value. Although, I don't think this is very good user experience.
A better solution would to be use some validators and inform the user that the input needs to be corrected, rather than just reverting the value back to the previous value.
Google up "wpf validation" or start with this SO question: WPF Data Binding and Validation Rules Best Practices
What is the base class of your class that defines the OutputFileName? That class' OnPropertyChange method seems to check if the property value really changed before firing the PropertyChanged event. I tried your example with a class that directly implements INotifyPropertyChanged and does
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("OutputFileName"));
}
and that works as you expect. Although i agree with Marc, showing a MessageBox from a property setter is rather uncommon.

How do you validate a clr property after it has been updated instead of before when implementing IDataErrorInfo?

I have implemented IDataErrorInfo in one of my classes to validate a property of that class. The property is bound to a control on my wpf user control. The validataion works fine, except there is one vital flaw.
It seems to be calling the IDataErrorInfo member public string this[string columnName] before the property is updated, so when I check the value of the property being changed it contains the previous value not the one just entered. Therefore, the validation is always one step behind. This means that I can't check for incorrect values that have just been entered.
Is there any way of forcing this validation to be called after the property has been updated and not before. I have tried changing the UpdateSourceTrigger to both LostFocus and PropertyChanged but they still report the previous value, just at different times.
Thanks.
The behavior that you are referring to can be reproduced when property change notifications are sent before the property is assigned.
public string FirstName
{
get { return _firstName; }
set
{
if (this.PropertyChanged != null)
{
this.PropertyChanged
(this, new PropertyChangedEventArgs("FirstName"));
}
_firstName = value;
}
}
May be calling the change notification after you have actually set the value may do the trick. And just for the record I don't call property changed notification like this!

Categories

Resources