使用IDataErrorInfo验证整个对象

时间:2013-12-06 23:41:40

标签: c# wpf idataerrorinfo

我在我的类中实现了一个IDataErrorInfo接口来验证对象。但我现在要做的是以编程方式验证整个对象以了解它是否有效。 我一直在谷歌搜索,但找不到任何东西。我以为我可以做像object.Validate()这样的事情,并知道它是否有效,但IDataErrorInfo不提供任何类似的方法。

我已经使用XAML验证它,但我也需要在方法中检查它。

有人可以帮助我实现这个目标吗?以防万一,这是我的班级:

    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;
            }
        }
    }
}

扩展解决方案:

也许我没有解释得很好,但我需要的是知道对象是否有任何验证错误。基于ethicallogics解决方案,我创建了一个名为IsValid的新方法,在那里我检查字典上是否有任何错误:

public bool IsValid()
    {
        ValidateProperty("AreaCode");
        ValidateProperty("PhoneNumber");
        ValidateProperty("PhoneTypeID");

        return Errors.Count == 0 ? true : false;
    }

为了实现这一点,我不得不更改ValidateProperty方法,以便不再在字典中添加错误键(或者您将获得异常)。然后我首先检查错误是否已经在字典中,并且只有在它没有时才添加它:

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);
    }

3 个答案:

答案 0 :(得分:2)

首先,您的班级必须实施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");

    }
}
xaml绑定中的

ValidateOnDataErrors必须为True

 <TextBox x:Name="PhoneNumber" Text="{Binding PhoneNumber, ValidatesOnDataErrors=True}"/>

这里我返回了简单的字符串而不是你的ErrorMessage,因为我不知道它是什么,你可以简单地用你的ErrorMessage替换字符串。我希望这会给你一个想法。

答案 1 :(得分:0)

来自ReactiveUI的

ReactiveValidatedObject有一个IsObjectValid方法可以满足你的需要。您可以使用它,或调整该代码。

答案 2 :(得分:0)

// you can implement this Vali class in any of your classes
// which you need to check their validation

// Vali class will loop throw the properties of any another  class 
// which implement it. and check their validations
// and has IsValid which return the state of validation 
// return true if valid

public abstract class Vali {
    public bool IsValid {
        get {
            PropertyInfo propInfo = GetType().GetProperty("Error");
            object itemValue = propInfo.GetValue(this , null);

            string iiiii = (string)itemValue;

            foreach (PropertyInfo prop in GetType().GetProperties()) {
                if (!String.IsNullOrWhiteSpace(met(prop.Name))) {
                    //MessageBox.Show("تاكد من صحة البيانات");
                    return false;
                }
            }
            return true;

        }

    }
    public abstract string met(string columnName);
}

// as example your class will be like this  
public class Phone : Vali , 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 {
            return met(columnName);
        }
    }

    public override string met(string columnName)
    {
        if (columnName == "AreaCode") {
            if (string.IsNullOrWhiteSpace(AreaCode))
                Error = ErrorMessages.ErrorMessage(ErrorMessages.FieldIsRequired , PhoneNameDictionary.GetValue(columnName));
        }
        if (columnName == "PhoneTypeID") {
            if (!PhoneTypeID.HasValue)
                Error = ErrorMessages.ErrorMessage(ErrorMessages.FieldIsRequired , PhoneNameDictionary.GetValue(columnName));
        }
        if (columnName == "PhoneNumber") {
            if (!PhoneNumber.HasValue)
                Error = ErrorMessages.ErrorMessage(ErrorMessages.FieldIsRequired , PhoneNameDictionary.GetValue(columnName));
        }

        return Error;
    }
}

class sdfasfd
{
    public sdfasfd()
    {
        // u can do this in ur code
        Phone p = new Phone();
        //assign properties here for p
        MessageBox.Show(p.IsValid.ToString());
    }
}