I implemented a IDataErrorInfo interface in my class to validate the objects. But what I want to do now, is to validate a whole object programatically to know if it´s valid or not. I have been searching in google but can´t find anything. I thought I could do something like a object.Validate() and know if its valid, but IDataErrorInfo does not provides any method like that.
I already validate it using XAML, but I need to check it in a method too.
Can anybody help me to achieve this? Just in case, this is my class:
namespace Plutus.Data.Domain
{
using Plutus.Data.Domain.NameMappings;
using Plutus.Data.Domain.Validation;
using System;
using System.ComponentModel;
public class Phone : IDataErrorInfo
{
/// <summary>
/// Código de área.
/// </summary>
public string AreaCode { get; set; }
/// <summary>
/// Identificador de tipo de teléfono.
/// </summary>
public short? PhoneTypeID { get; set; }
/// <summary>
/// Número de teléfono.
/// </summary>
public long? PhoneNumber { get; set; }
/// <summary>
/// Número de interno.
/// </summary>
public string ExtensionNumber { get; set; }
public string Error { get { return null; } }
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "AreaCode")
{
if (string.IsNullOrWhiteSpace(AreaCode))
result = ErrorMessages.ErrorMessage(ErrorMessages.FieldIsRequired, PhoneNameDictionary.GetValue(columnName));
}
if (columnName == "PhoneTypeID")
{
if (!PhoneTypeID.HasValue)
result = ErrorMessages.ErrorMessage(ErrorMessages.FieldIsRequired, PhoneNameDictionary.GetValue(columnName));
}
if (columnName == "PhoneNumber")
{
if (!PhoneNumber.HasValue)
result = ErrorMessages.ErrorMessage(ErrorMessages.FieldIsRequired, PhoneNameDictionary.GetValue(columnName));
}
return result;
}
}
}
}
EXTENDED SOLUTION:
Maybe I didnt explain very good, but what I needed was to know if an object has any validation error or not. Based on ethicallogics solution, I created a new method called IsValid, where I check if there is any error on the dictionary:
public bool IsValid()
{
ValidateProperty("AreaCode");
ValidateProperty("PhoneNumber");
ValidateProperty("PhoneTypeID");
return Errors.Count == 0 ? true : false;
}
To implement this, I had to change the ValidateProperty method so as not to add again the error key in the dictionary (or you will get an exception). Then I checked first if the error is already in the dictionary, and I add it only if it doesnt:
public void ValidateProperty(string propertyName)
{
if (propertyName == "AreaCode" && string.IsNullOrWhiteSpace(AreaCode))
{
if (!Errors.ContainsKey(propertyName))
Errors.Add(propertyName, ErrorMessages.ErrorMessage(ErrorMessages.FieldIsRequired, PhoneNameDictionary.GetValue(propertyName)));
}
else if (propertyName == "PhoneTypeID" && !PhoneTypeID.HasValue)
{
if (!Errors.ContainsKey(propertyName))
Errors.Add(propertyName, ErrorMessages.ErrorMessage(ErrorMessages.FieldIsRequired, PhoneNameDictionary.GetValue(propertyName)));
}
else if (propertyName == "PhoneNumber" && !PhoneNumber.HasValue)
{
if (!Errors.ContainsKey(propertyName))
Errors.Add(propertyName, ErrorMessages.ErrorMessage(ErrorMessages.FieldIsRequired, PhoneNameDictionary.GetValue(propertyName)));
}
else if (Errors.ContainsKey(propertyName))
Errors.Remove(propertyName);
}
First your class must implement INotifyPropertyChanged
public class Phone : IDataErrorInfo, INotifyPropertyChanged
{
string areaCode;
public string AreaCode
{
get
{
return areaCode;
}
set
{
if (areaCode != value)
{
areaCode = value;
ValidateProperty("AreaCode"); //Validate on PropertyChanged
Notify("AreaCode");
}
}
}
short? phoneTypeId;
public short? PhoneTypeID
{
get
{
return phoneTypeId;
}
set
{
if (phoneTypeId != value)
{
phoneTypeId = value;
ValidateProperty("PhoneTypeID");
Notify("PhoneTypeID");
}
}
}
long? phoneNumber;
public long? PhoneNumber
{
get
{
return phoneNumber;
}
set
{
if (phoneNumber != value)
{
phoneNumber = value;
ValidateProperty("PhoneNumber");
Notify("PhoneNumber");
}
}
}
string extensionNumber;
public string ExtensionNumber
{
get
{
return extensionNumber;
}
set
{
if (extensionNumber != value)
extensionNumber = value; Notify("ExtensionNumber");
}
}
public string Error { get { return null; } }
Dictionary<string, string> errors = new Dictionary<string, string>();
public string this[string columnName]
{
get
{
if(errors.ContainsKey(columnName)
return errors[columnName];
return null;
}
}
public event PropertyChangedEventHandler PropertyChanged;
void Notify(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
//This could be much more generic but for simplicity
void ValidateProperty(string propertyName)
{
if (propertyName=="AreaCode" && string.IsNullOrWhiteSpace(AreaCode))
errors.Add(propertyName,"AreaCode is Mandatory");
else if (propertyName == "PhoneNumber" && !PhoneNumber.HasValue)
errors.Add(propertyName, "PhoneNumber can not be null");
else if(propertyName == "PhoneTypeID" && !PhoneTypeID.HasValue)
errors.Add(propertyName, "PhoneTypeID can not be null");
else if(errors.ContainsKey(propertyName))
errors.Remove(propertyName);
}
public void ValidatePhoneObject()
{
ValidateProperty("AreaCode");
ValidateProperty("PhoneNumber");
ValidateProperty("PhoneTypeID");
//Must fire property changed so that binding validation System calls IDataErrorInfo indexer
Notify("AreaCode");
Notify("PhoneNumber");
Notify("PhoneTypeID");
}
}
in xaml binding ValidateOnDataErrors must be True
<TextBox x:Name="PhoneNumber" Text="{Binding PhoneNumber, ValidatesOnDataErrors=True}"/>
Here I have returned simple string instead of your ErrorMessage because I dont have idea what it is , you can simply replace string with your ErrorMessage. I hope this will give you an idea.