将验证错误从一个属性传递到另一个属性

时间:2016-05-22 06:45:11

标签: c# wpf validation fluentvalidation

我有一个名为Person的类,如下所示,使用Fluent验证进行验证:

注意 :我在Person类中实现了INotifyPropertyChanged,但为了简单起见,我没有在此处显示,因此我的代码看起来很简单。

public class Person : ObjectBase
{
    public int PersonId {get; set;}
    public string Name {get; set;}
    public int Age {get; set;}

    class PersonValidator : AbstractValidator<Person>
    {
        public PersonValidator()
        {
            RuleFor(x => x.Name).NotEmpty();
            RuleFor(x => x.Age).GreaterThan(0);
        }
    }
}

现在在ViewModel中:

public Class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
        NewPerson = new Person();
    }

    private Person _newPerson;
    public Person NewPerson
    {
        get
        {
            return _newPerson;
        }
        set
        {
            if(_newPerson != value)
            {
                _newPerson = value;
                OnPropertyChanged(() => NewPerson();
            }
        }
    }

    public string AgeString
    {
        get
        {
            return NewPerson.Age.ToString();
        }
        set
        {
            if(value == null)
            {
                NewParty.Age = 0;
            }
            else if(NewPerson.Age.ToString() != value)
            {
                int age = 0;
                bool canParse = Int32.TryParse(value, out age);

                if(canParse)
                    NewParty.Age = age;
                else
                    NewParty.age = 0;
            }

            OnPropertyChanged(() => AgeString);

        }
    }

}

在视图中:

<Window ..........>
    <Textbox Text = {Binding NewPerson.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true} />
    <Textbox Text = {Binding AgeString, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true} />
</Window>

现在您可以在上面的XAML中看到,我的第二个文本框没有绑定到NewPerson.Age,而是绑定到AgeString。

现在有些人可能会问我为什么要这样做? 我这样做是因为如果我将我的文本框绑定到NewPerson.Age,那么当textBox被用户保持为空时我无法验证它。所以,我必须将此文本框绑定到字符串属性。

无论如何,我的文本框绑定到AgeString属性。当用户输入任何垃圾值时,它显示为零。太棒了。

回顾Person类及其验证。我已经验证了Age Proerty大于0.现在我想对AgeString属性做同样的事情。

所以,我的问题是如何将此验证错误从NewPerson.Age传递给AgeString属性????

更新

正如第一条评论中所建议的那样,我使用的是Value Converter而不是一个不同的属性。

这是我更新的ViewModel:

public Class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
        NewPerson = new Person();
        SetTo18Command = new RelayCommand(SetTo18());
    }

    public RelayCommand SetTo18Command {get;set;}

    private Person _newPerson;
    public Person NewPerson
    {
        get
        {
            return _newPerson;
        }
        set
        {
            if(_newPerson != value)
            {
                _newPerson = value;
                OnPropertyChanged(() => NewPerson();
            }
        }
    }    

    private void SetTo18()
    {
        NewPerson.Age = 18;
    }
}

查看:

<Window ..........>

    <Textbox Text = "{Binding NewPerson.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true}" />
    <Textbox Text = "{Binding NewPerson.Age, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true}" />

    <Button Command="{Binding SetTo18Command}" Content="Set to 18" />

</Window>

当我点击重置按钮时,它会将NewPerson的年龄设置为18。

这是我的ValueConverter:

public class StringToIntConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null || value == DependencyProperty.UnsetValue)
            return 0;

        int output = 0;
        bool canParse = Int32.TryParse(value.ToString(), out output);

        if (canParse)
            return output;
        else
            return 0;
    }
}

这很好用。但是有一个小错误。

当我在文本框中将人的年龄设置为0然后我点击SetTo18按钮时,文本框的值更改为18,但我仍然看到文本框周围出现错误的红色边框。

这是我的Validation Class,它实现了IDataErrorInfo:

public abstract class ObjectBase : IDataErrorInfo
{
    public ObjectBase()
    {
        _Validator = GetValidator();
        Validate();
    }

    protected bool _IsDirty = false;
    protected IValidator _Validator = null;

    protected IEnumerable<ValidationFailure> _ValidationErrors = null;
    protected virtual IValidator GetValidator()
    {
        return null;
    }

    [NotNavigable]
    public IEnumerable<ValidationFailure> ValidationErrors
    {
        get { return _ValidationErrors; }
        set { }
    }

    public void Validate()
    {
        if (_Validator != null)
        {
            ValidationResult results = _Validator.Validate(this);
            _ValidationErrors = results.Errors;
        }
    }

    [NotNavigable]
    public virtual bool IsValid
    {
        get
        {
            if (_ValidationErrors != null && _ValidationErrors.Count() > 0)
                return false;
            else
                return true;
        }
    }

    string IDataErrorInfo.Error
    {
        get { return string.Empty; }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            StringBuilder errors = new StringBuilder();

            if (_ValidationErrors != null && _ValidationErrors.Count() > 0)
            {
                foreach (ValidationFailure validationError in _ValidationErrors)
                {
                    if (validationError.PropertyName == columnName)
                        errors.AppendLine(validationError.ErrorMessage);
                }
            }

            return errors.ToString();
        }
    }
}

0 个答案:

没有答案