当前位置:  开发笔记 > 编程语言 > 正文

强制INotifyDataErrorInfo验证

如何解决《强制INotifyDataErrorInfo验证》经验,为你挑选了1个好方法。

我完全按照以下链接中的描述实现了INotifyDataErrorInfo:

http://blog.micic.ch/net/easy-mvvm-example-with-inotifypropertychanged-and-inotifydataerrorinfo

我有一个TextBox绑定到我的模型中的字符串属性.

XAML


模型

private string _fullName;
public string FullName
{
    get { return _fullName; }
    set
    {
        // Set raises OnPropertyChanged
        Set(ref _fullName, value);

        if (string.IsNullOrWhiteSpace(_fullName))
            AddError(nameof(FullName), "Name required");
        else
            RemoveError(nameof(FullName));                
    }
}

INotifyDataError代码

private Dictionary> _errors = new Dictionary>();

public event EventHandler ErrorsChanged;

// get errors by property
public IEnumerable GetErrors(string propertyName)
{
    if (_errors.ContainsKey(propertyName))
        return _errors[propertyName];
    return null;
}

public bool HasErrors => _errors.Count > 0;

// object is valid
public bool IsValid => !HasErrors;

public void AddError(string propertyName, string error)
{
    // Add error to list
    _errors[propertyName] = new List() { error };
    NotifyErrorsChanged(propertyName);
}

public void RemoveError(string propertyName)
{
    // remove error
    if (_errors.ContainsKey(propertyName))
        _errors.Remove(propertyName);
    NotifyErrorsChanged(propertyName);
}

public void NotifyErrorsChanged(string propertyName)
{
    // Notify
    if (ErrorsChanged != null)
       ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}

现在这一切都运行正常,但只有在我的TextBox中输入内容时才会验证.我想要一些方法来按需验证,甚至没有触摸文本框,比如按一下按钮.

我已经尝试过为我的所有属性提升PropertyChanged,如本问题所述,但它没有检测到错误.我不知何故需要调用我的属性设置器,以便可以检测到错误.我正在寻找一个MVVM解决方案.



1> Simon Mourie..:

你使用的INotifyDataErrorInfo实现有点瑕疵恕我直言.它依赖于附加到对象的状态(列表)中保存的错误.存储状态的问题有时在移动的世界中,您没有机会在需要时更新它.这是另一个MVVM实现,它不依赖于存储状态,但可以动态计算错误状态.

由于您需要将验证代码放在一个集中的GetErrors方法中(您可以创建从此中心方法调用的每个属性验证方法),而不是在属性设置器中,因此处理的方式有所不同.

public class ModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
{
    public event PropertyChangedEventHandler PropertyChanged;
    public event EventHandler ErrorsChanged;

    public bool HasErrors
    {
        get
        {
            return GetErrors(null).OfType().Any();
        }
    }

    public virtual void ForceValidation()
    {
        OnPropertyChanged(null);
    }

    public virtual IEnumerable GetErrors([CallerMemberName] string propertyName = null)
    {
        return Enumerable.Empty();
    }

    protected void OnErrorsChanged([CallerMemberName] string propertyName = null)
    {
        OnErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
    }

    protected virtual void OnErrorsChanged(object sender, DataErrorsChangedEventArgs e)
    {
        var handler = ErrorsChanged;
        if (handler != null)
        {
            handler(sender, e);
        }
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(sender, e);
        }
    }
}


这里有两个示例类,演示如何使用它:

public class Customer : ModelBase
{
    private string _name;

    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            if (_name != value)
            {
                _name = value;
                OnPropertyChanged();
            }
        }
    }

    public override IEnumerable GetErrors([CallerMemberName] string propertyName = null)
    {
        if (string.IsNullOrEmpty(propertyName) || propertyName == nameof(Name))
        {
            if (string.IsNullOrWhiteSpace(_name))
                yield return "Name cannot be empty.";
        }
    }
}

public class CustomerWithAge : Customer
{
    private int _age;
    public int Age
    {
        get
        {
            return _age;
        }
        set
        {
            if (_age != value)
            {
                _age = value;
                OnPropertyChanged();
            }
        }
    }

    public override IEnumerable GetErrors([CallerMemberName] string propertyName = null)
    {
        foreach (var obj in base.GetErrors(propertyName))
        {
            yield return obj;
        }

        if (string.IsNullOrEmpty(propertyName) || propertyName == nameof(Age))
        {
            if (_age <= 0)
                yield return "Age is invalid.";
        }
    }
}

它就像一个带有简单XAML的魅力,如下所示:



(UpdateSourceTrigger是可选的,如果你不使用它,它只会在焦点丢失时起作用).

使用此MVVM基类,您不必强制进行任何验证.但是,如果你需要它,我在ModelBase中添加了一个ForceValidation示例方法应该可以工作(我已经测试了它,例如像_name这样的成员值,如果没有通过公共setter就会被更改).

推荐阅读
Chloemw
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有