WPF IDataErrorInfo HasError和必填字段的不同控件样式

时间:2014-01-10 18:54:03

标签: wpf validation idataerrorinfo

我在我的实体类中使用IDataErrorInfo来验证实体对象。我有这个工作,并使用Validation.ErrorTemplate以我想要的每个控件的视觉样式显示任何验证问题。

例如TextBox控件我使用Validation.ErrorTemplate来装饰带有红色边框的TextBox和带有描述验证错误的工具提示的感叹号图标。

现在我想稍微软化一下UI的外观。当用户打开数据输入表单时,我想将所需字段的背景颜色更改为浅蓝色。我不想将Validation.ErrorTemplate与一个刺耳的红色边框和感叹号一起使用,直到他们至少在TextBox中输入一些无法验证的数据。

我想在实体类中保留验证和必需的字段逻辑,并保持UI声明。是否有我可以使用的模式或我需要关注此功能的其他类?我正在使用Validation.HasError上的TextBox样式中的DataTrigger和MultiValueConveter来检查我是否有验证错误,并且控件的值为null或空字符串,但没有很多运气,似乎应该是一种更简单的方法。

例如,我实现IDataErrorInfo的实体类返回验证错误,例如"电子邮件地址是必需的"如果Email属性为null或为空,则另一个验证错误,例如"电子邮件地址似乎没有正确格式化#34;当Email属性设置为不验证为有效电子邮件地址的字符串时。如果Email属性设置为null或为空,我想将Background设置为LightBlue。如果Email属性中有一个字符串,但它不是有效的电子邮件地址,我想显示Validation.ErrorTemplate。

EDIT

public class MyEntity : IDataErrorInfo
{
    private static readonly IList<PropertyInfo> BindableProperties;

    static MyEntity()
    {
        BindableProperties = typeof(MyEntity).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite).ToList();
    }

    public string Email { get; set; }

    public Boolean IsValid()
    {
        return BindableProperties.All(p => this[p.Name] == null);
    }

    #region // IDataErrorInfo Members

    public string this[string name]
    {
        get
        {
            string message = null;

            switch (name)
            {
                ...

                case "Email":

                    if (!string.IsNullOrEmpty(Email))
                    {
                        try
                        {
                            new System.Net.Mail.MailAddress(Email);
                        }
                        catch
                        {
                            message = "Email does not appear to be a valid email address.";
                            break;
                        }
                    }
                    else
                    {
                        message = "Email is required";
                    }

                    break;

                ...
            }

            return message;
        }
    }

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    #endregion // IDataErrorInfo Members
}

public class MyEntity : IDataErrorInfo { private static readonly IList<PropertyInfo> BindableProperties; static MyEntity() { BindableProperties = typeof(MyEntity).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite).ToList(); } public string Email { get; set; } public Boolean IsValid() { return BindableProperties.All(p => this[p.Name] == null); } #region // IDataErrorInfo Members public string this[string name] { get { string message = null; switch (name) { ... case "Email": if (!string.IsNullOrEmpty(Email)) { try { new System.Net.Mail.MailAddress(Email); } catch { message = "Email does not appear to be a valid email address."; break; } } else { message = "Email is required"; } break; ... } return message; } } public string Error { get { throw new NotImplementedException(); } } #endregion // IDataErrorInfo Members }

控制XAML

<TextBox Name="EmailTextBox" Text="{Binding MyEntity.Email, ValidatesOnDataErrors=True}"/>

<Button x:Name="SaveButton" Command="Save" Content="Save">
    <Button.CommandBindings>
        <CommandBinding Command="Save" Executed="Save_Executed" CanExecute="Save_CanExecute"/>
    </Button.CommandBindings>
</Button>

代码背后 <TextBox Name="EmailTextBox" Text="{Binding MyEntity.Email, ValidatesOnDataErrors=True}"/> <Button x:Name="SaveButton" Command="Save" Content="Save"> <Button.CommandBindings> <CommandBinding Command="Save" Executed="Save_Executed" CanExecute="Save_CanExecute"/> </Button.CommandBindings> </Button>

1 个答案:

答案 0 :(得分:0)

请为您的Entity.Here Employee是一个实体。

public class Employee : INotifyPropertyChanged,IDataErrorInfo
{
    private static readonly IList<PropertyInfo> BindableProperties;

    static Employee()
    {
        BindableProperties = typeof(Employee).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite).ToList();
    }

    string email;

    public string Email
    {
        get { return email; }
        set {
            email = value; 
            Validate(true,"Email");
            Notify("Email");
        }
    }

    public Boolean IsValid()
    {
        return BindableProperties.All(p => Validate(false,p.Name));
    }

    bool Validate(bool addErrors, string propName)
    {
        string message = string.Empty;

        switch (propName)
        {
            case "Email":
                if (!string.IsNullOrEmpty(Email))
                {
                    try
                    {
                        new System.Net.Mail.MailAddress(Email);
                    }
                    catch
                    {
                        message = "Email does not appear to be a valid email address.";
                        break;
                    }
                }
                else
                {
                    message = "Email is required";
                }
                break;
        }

        if (addErrors)
            AddOrRemoveError(propName, message);

        return string.IsNullOrEmpty(message);
    }

    void AddError(string propertyName, string error)
    {
        if (!errors.ContainsKey(propertyName))
            errors.Add(propertyName, error);
    }

    void RemoveError(string propertyName)
    {
        if (errors.ContainsKey(propertyName))
            errors.Remove(propertyName);
    }

    void AddOrRemoveError(string propName,string message)
    {
        if (!string.IsNullOrEmpty(message))
            AddError(propName, message);
        else
            RemoveError(message);
    }

    private Dictionary<string, string> errors = new Dictionary<string, string>();

    public event PropertyChangedEventHandler PropertyChanged;

    void Notify(string propName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    public string this[string columnName]
    {
        get { if(errors.ContainsKey(columnName)) return errors[columnName]; else return null;}
    }
}