首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用IDataErrorInfo取代INotifyDataErrorInfo

用IDataErrorInfo取代INotifyDataErrorInfo
EN

Stack Overflow用户
提问于 2019-10-21 22:29:32
回答 2查看 590关注 0票数 0

我有一个名为Person的类,它有两个属性FirstNameLastName,两个Constructors、一个ICommand以及INotifyPropertyChangedIDataErrorInfo通常需要的东西

代码语言:javascript
复制
class Person : ObservableCollection<Person>, INotifyPropertyChanged, IDataErrorInfo
{
    string firstName, lastName;

    #region Properties
    [Required(ErrorMessage = "First Name is Required")]
    [RegularExpression("test", ErrorMessage = "It's to be test")]
    public string FirstName {
        get => firstName;
        set { firstName = value; OnPropertyChanged(); }
    }

    [Required]
    [RegularExpression("test", ErrorMessage = "It also has to be test")]
    public string LastName {
        get => lastName;
        set { lastName = value; OnPropertyChanged(); }
    }
    #endregion Properties
   
    #region Constructors
    public Person(){
        AddToList = new Command(CanAdd, Add);
    }

    public Person(string fName, string lName){
        FirstName = fName;
        LastName = lName;
    }
    #endregion Constructors

    #region Command
    public ICommand AddToList { get; set; }
    bool CanAdd(object para) => Validator.TryValidateObject(this, new ValidationContext(this), null, true);
    void Add(object para){
        Add(new Person(FirstName, LastName));
        FirstName = LastName = null;
    }
    #endregion Command

    #region INotifyPropertyChanged
    public new event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    #endregion INotifyPropertyChanged

    #region IDataErrorInfo
    public string Error => null;
    public string this[string columnName] {
        get {
            var ValidationResults = new List<ValidationResult>();
            if (Validator.TryValidateProperty(
                    GetType().GetProperty(columnName).GetValue(this),
                    new ValidationContext(this) { MemberName = columnName },
                    ValidationResults
                )) return null;

            return ValidationResults.First().ErrorMessage;
        }
    }
    #endregion IDataErrorInfo
}

xaml中,我有两个TextBox绑定到FirstNameLastName of Person,两个Label用于验证错误消息,还有一个Button绑定到ICommand,以在下面的ListView中添加Person

代码语言:javascript
复制
<Window ...>
    <Window.Resources>
        <local:Person x:Key="Person"/>
    </Window.Resources>

    <Grid DataContext="{StaticResource Person}">
        <StackPanel>
            <TextBox x:Name="Fname" Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
            <Label Content="{Binding (Validation.Errors)[0].ErrorContent, ElementName=Fname}"/>

            <TextBox x:Name="Lname" Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>
            <Label Content="{Binding (Validation.Errors).CurrentItem.ErrorContent, ElementName=Lname}"/>
        
            <Button Content="Click" Command="{Binding AddToList}" />
        
            <ListView x:Name="lv" ItemsSource="{Binding}">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="First Name" Width="200" 
                            DisplayMemberBinding="{Binding FirstName}"/>
                        <GridViewColumn Header="Last Name" Width="200" 
                            DisplayMemberBinding="{Binding LastName}" />
                    </GridView>
                </ListView.View>
            </ListView>
        </StackPanel>
    </Grid>
</Window>

它有效,如果“名名”和“名名”无效,并且只要“名名”和“姓”都是无效的,则“按钮”仍然是禁用的。我只想用IDataErrorInfo替换INotifyDataErrorInfo部件。为了保持相同的功能,我必须对Person类和xaml进行哪些更改?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-23 13:59:34

框架每次引发GetErrors事件时都调用ErrorsChanged。由于有一个HasErrors属性应该在出现验证错误时返回true,所以在属性设置器中进行验证并将验证错误缓存到Dictionary<string, List<ValidationResult>>中是有意义的。

请参阅以下示例实现:

代码语言:javascript
复制
class Person : ObservableCollection<Person>, INotifyPropertyChanged, INotifyDataErrorInfo
{
    string firstName, lastName;

    #region Properties
    [Required(ErrorMessage = "First Name is Required")]
    [RegularExpression("test", ErrorMessage = "It's to be test")]
    public string FirstName
    {
        get => firstName;
        set { firstName = value; OnPropertyChanged(); Validate(); }
    }

    [Required]
    [RegularExpression("test", ErrorMessage = "It also has to be test")]
    public string LastName
    {
        get => lastName;
        set { lastName = value; OnPropertyChanged(); Validate(); }
    }
    #endregion Properties

    #region Constructors
    public Person()
    {
        AddToList = new Command(CanAdd, Add);
        Validate(nameof(FirstName));
        Validate(nameof(LastName));
    }

    public Person(string fName, string lName)
    {
        FirstName = fName;
        LastName = lName;
    }
    #endregion Constructors

    #region Command
    public ICommand AddToList { get; set; }
    bool CanAdd(object para) => _validationResults.Count == 0;
    void Add(object para)
    {
        base.Add(new Person(FirstName, LastName));
        FirstName = LastName = null;
    }
    #endregion Command

    #region INotifyPropertyChanged
    public new event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    #endregion INotifyPropertyChanged

    #region INotifyDataErrorInfo
    private readonly Dictionary<string, List<ValidationResult>> _validationResults = new Dictionary<string, List<ValidationResult>>();

    public bool HasErrors => _validationResults.Count > 0;

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
        if (_validationResults.TryGetValue(propertyName, out List<ValidationResult> validationResults))
            return new string[1] { validationResults.First().ErrorMessage };
        return null;
    }

    private void Validate([CallerMemberName]string propertyName = "")
    {
        var ValidationResults = new List<ValidationResult>();
        if (Validator.TryValidateProperty(typeof(Person).GetProperty(propertyName).GetValue(this),
                new ValidationContext(this) { MemberName = propertyName }, ValidationResults))
        {
            _validationResults.Remove(propertyName);
        }
        else
        {
            _validationResults[propertyName] = ValidationResults;
        }
        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
    }
    #endregion
}
票数 0
EN

Stack Overflow用户

发布于 2019-10-24 01:18:48

不知道它是否好,但如果我用以下内容替换IDataErrorInfo区域:

代码语言:javascript
复制
#region IDataErrorInfo
public bool HasErrors => true;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
    var ValidationResults = new List<ValidationResult>();
    if (Validator.TryValidateProperty(GetType().GetProperty(propertyName).GetValue(this),
            new ValidationContext(this) { MemberName = propertyName }, ValidationResults))
        return null;

    return new string[1] { ValidationResults.First().ErrorMessage };
}
#endregion IDataErrorInfo

不要碰任何其他部件,它也能工作!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58494893

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档