I have build my own custom validation framework for WPF using attribute based validation. I am stuck on the last step which is to highlight the TextBox. Actually, it does highlight the textboxes but all the textboxes are dependent on a single property HasError.
public class RegistrationViewModel : ViewModel
{
[NotNullOrEmpty("FirstName should not be null or empty")]
public string FirstName { get; set; }
[NotNullOrEmpty("Middle Name is required!")]
public string MiddleName { get; set; }
[NotNullOrEmpty("LastName should not be null or empty")]
public string LastName { get; set; }
public bool HasError
{
get
{
**return Errors.Count > 0; // THIS IS THE PROBLEM**
}
}
}
And here is the XAML code:
<Style x:Key="textBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=HasError}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
The problem with the above code is that it will highlight all the textboxes that uses "textBoxStyle" even though they are valid. This is because the HasError does not validate on individual property basis but as a whole.
Any ideas?
UPDATE 1:
The ViewModel contains the Errors collection:
public class ViewModel : ContentControl, INotifyPropertyChanged
{
public static DependencyProperty ErrorsProperty;
static ViewModel()
{
ErrorsProperty = DependencyProperty.Register("Errors", typeof(ObservableCollection<BrokenRule>), typeof(ViewModel));
}
public ObservableCollection<BrokenRule> Errors
{
get { return (ObservableCollection<BrokenRule>)GetValue(ErrorsProperty); }
set
{
SetValue(ErrorsProperty,value);
OnPropertyChanged("HasError");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
UPDATE 2:
My validation engine:
public bool Validate(object viewModel)
{
_brokenRules = new List<BrokenRule>();
// get all the properties
var properties = viewModel.GetType().GetProperties();
foreach(var property in properties)
{
// get the custom attribute
var attribues = property.GetCustomAttributes(typeof (EStudyValidationAttribute), false);
foreach(EStudyValidationAttribute att in attribues)
{
bool isValid = att.IsValid(property.GetValue(viewModel,null));
if(isValid) continue;
// add the broken rule
var brokenRule = new BrokenRule()
{
PropertyName = property.Name,
Message = att.Message
};
_brokenRules.Add(brokenRule);
}
}
var list = _brokenRules.ToObservableCollection();
viewModel.GetType().GetProperty("Errors").SetValue(viewModel,list,null);
return (_brokenRules.Count() == 0);
}
Best Answer
You can implement IDataErrorInfo interface in your ViewModels, and in XAML check attached properties Validation.HasError on elements for controls with validation error; it's better because it's standart mechanizm in .Net.
When binding to property in TextBoxes, you need to set binding ValidatesOnDataError property to true.
You can even use your implemented validation method, but check validation by property.