I have seen two ways of doing data validation in .Net 4.0.Currently Iam using IDataErrorInfo like this but the problem here is "this" of IDataErrorInfo is called only when getter of Age property is called.I have some logic in the setter which is dependent on valid value of Age.
public int Age
{
get { return _age; }
set
{
_age = value;
OnPropertyChanged("Age");
//My methods to call when Age is valid
}
}
public string this[string columnName]
{
get
{
string error = null;
switch (columnName)
{
case "Age":
if (Age < 10 || Age > 100)
error="The age must be between 10 and 100";
break;
}
return error;
}
}
I can't call those methods as validation is not done when setter is called ,its done only when getter is called.Can somebody help me understand why its designed like that.In my opinion validation should be close to setter where value is assigned.
I am bound to change my implementation to this ,using Exception validation
public int Age
{
get { return _age; }
set
{
if (value < 10 || value > 100)
throw new ArgumentException("The age must be between 10 and 100");
_age = value;
//My methods to call when Age is valid
}
}
I am asking this question because the existing implementation is based on IDataErrorInfo in my project and there are lot of properties getting validated.Is there some solution which will let me keep IDataerrorInfo implementation and achieve the same I achieve from doing exception validation.
I do not want to throw exception on my property setters because its a design guideline by microsoft
Do not use exceptions for normal flow of control, if possible. Except for system failures and operations with potential race conditions, framework designers should design APIs so that users can write code that does not throw exceptions. For example, you can provide a way to check preconditions before calling a member so that users can write code that does not throw exceptions.
and also I don't want to throw exceptions which I do not catch in my viewmodel code only.
This is my xaml
<TextBox Text="{Binding Age, ValidatesOnDataErrors=True,
NotifyOnValidationError=True, ValidatesOnExceptions=True,
UpdateSourceTrigger=PropertyChanged}"/>
Binding first sets the value and then it calls the getter aaand then indexer is being called to validate. However your issue is that you wish the indexer to come first. That is not how wpf works.
Basically wpf gives you all freedom when using IDataErrorInfo therefore you have to implement all by yourself. Let me show you just an example:
public int Age
{
get { return _age; }
set
{
int oldVal = _age;
_age = value;
if(Validate("Age") == null)
{
// Do whatever you want
OnPropertyChanged("Age");
}
else
{
// You can rollback value or not, it wouldnt matter...
// PropertyChanged will not be fired!!!
_age = oldVal;
}
}
}
public string this[string columnName]
{
get
{
return Validate(columnName);
}
}
public string Validate(string propertyName)
{
string error = null;
switch (propertyName)
{
case "Age":
if (_age< 10 || _age > 100)
error = "The age must be between 10 and 100";
}
return error;
}