【问题标题】:Data Validation in mvvmmvvm 中的数据验证
【发布时间】:2013-08-04 09:27:14
【问题描述】:

我有一个包含多个 ViewModel 的应用程序。某些属性具有 DataAnnotations。

 [Required(ErrorMessage = "Field 'Range' is required.")]
    [Range(1, 10, ErrorMessage = "Field 'Range' is out of range.")]
    public int Password
    {
        get
        {
            return _password;
        }
        set
        {
            if (_password != value)
            {
                _password = value;
                RaisePropertyChanged("Password");
            }
        }
    }

如何通过为所有视图模型实现 IDataErrorInfo 或 INotifyDataErrorInfo 接口来完成验证?

我使用This 文章,但在属性更改时验证并且不验证必填字段。

【问题讨论】:

    标签: wpf validation mvvm mvvm-light idataerrorinfo


    【解决方案1】:

    这是一个使用IDataErrorInfo 的简单示例。这应该可以帮助您入门。

    XAML:

    <Grid>
        <Grid.Resources>
            <ControlTemplate x:Key="LeftErrorTemplate">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding AdornedElement.(Validation.Errors).[0].ErrorContent, ElementName=ErrorAdorner}" Background="Red" Foreground="White" FontWeight="Bold" VerticalAlignment="Center"/>
                    <AdornedElementPlaceholder x:Name="ErrorAdorner">
                        <Border BorderBrush="Red" BorderThickness="1" />
                    </AdornedElementPlaceholder>
                </StackPanel>
            </ControlTemplate>
        </Grid.Resources>
        <TextBlock Height="23" HorizontalAlignment="Left" Margin="158,66,0,0" Name="textBlock1" Text="Name" VerticalAlignment="Top" Width="44" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="217,65,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" 
                 Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" 
                 Validation.ErrorTemplate="{StaticResource LeftErrorTemplate}"/>
    </Grid>
    

    后面的代码:

    using System;
    using System.Windows;
    using System.ComponentModel;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var vm = new ViewModel();
    
                this.DataContext = vm;
            }
        }
    
        public class ViewModel : ObservableBase, IDataErrorInfo
        {
            private string _Name;
    
            public string Name
            {
                get { return _Name; }
                set
                {
                    _Name = value;
                    OnPropertyChanged("Name");
                }
            }
    
            public string Error
            {
                get { throw new NotImplementedException(); }
            }
    
            public string this[string columnName]
            {
                get
                {
                    string errorMessage = string.Empty;
    
                    switch (columnName)
                    {
                        case "Name":
                            if (string.IsNullOrEmpty(Name))
                                errorMessage = "Enter name";
                            else if (Name.Trim() == string.Empty)
                                errorMessage = "Enter valid name";
                            break;
                    }
                    return errorMessage;
                }
            }
    
        }
    
        public class ObservableBase : INotifyPropertyChanged
        {
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

    【讨论】:

    • 谢谢,但我想为所有应用程序和所有 ViewModel 继承的验证类创建一个验证类。
    【解决方案2】:

    您好,您必须在我的代码中创建一些验证注释的方法,如 ValidateMethod

    public class ViewModel:INotifyPropertyChanged,IDataErrorInfo
        {
            int _password;
    
            [Required(ErrorMessage = "Field 'Range' is required.")]
            [Range(1, 10, ErrorMessage = "Field 'Range' is out of range.")]
            public int Password
            {
                get
                {
                    return _password;
                }
                set
                {
                    if (_password != value)
                    {
                        _password = value;
                        Validate("Password", value);
                        Notify("Password");
                    }
                }
            }
    
            private void Validate(string propertyName, object value)
            {
                if (string.IsNullOrEmpty(propertyName))
                    throw new ArgumentNullException("propertyName");
    
                string error = string.Empty;
    
                var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(2);
    
                bool result = Validator.TryValidateProperty(
                    value,
                    new ValidationContext(this, null, null)
                    {
                        MemberName = propertyName
                    },
                    results);
    
                if (!result && (value == null || ((value is int || value is long) && (int)value == 0) || (value is decimal && (decimal)value == 0)))
                    return;
    
                if (!result)
                {
                    System.ComponentModel.DataAnnotations.ValidationResult validationResult = results.First();
                    if (!errorMessages.ContainsKey(propertyName))
                        errorMessages.Add(propertyName, validationResult.ErrorMessage);
                }
    
                else if (errorMessages.ContainsKey(propertyName))
                    errorMessages.Remove(propertyName);
            }
    
            #region INotifyPropertyChanged 
    
            public void Notify(string propName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propName));
    
            }
            public event PropertyChangedEventHandler PropertyChanged;
    
            #endregion
    
            #region IDataErrorInfo
    
            public string Error
            {
                get { throw new NotImplementedException(); }
            }
    
            private Dictionary<string, string> errorMessages = new Dictionary<string, string>();
    
            public string this[string columnName]
            {
                get 
                { 
                    if(errorMessages.ContainsKey(columnName))
                        return errorMessages[columnName];
                    return null;
    
                }
            }
    
            #endregion
        }
    

    >xaml

    <TextBox Text="{Binding Password, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" Height="70" Width="200" />
    

    xaml.cs

    public MainWindow()
        {
            InitializeComponent();
            DataContext = new ViewModel();
        }
    

    您需要从应用 DataAnnotations 的属性的设置器中调用 Validate 方法,并确保在通知 PropertyChanged 之前调用它。

    【讨论】:

    • 谢谢,但是 PropertyChanged 没有在要求的验证中通知,我应该在提交按钮中调用所有必需属性的验证方法。
    • 是的,您必须为所有要验证的属性调用它,并且您的意思是 PropertyChanged 没有在要求的验证中通知
    • 只有在绑定发生时才会触发验证。当用户启动屏幕并直接单击提交按钮时会发生什么......没有发生绑定,因此没有触发验证......
    • 您可以看到字典 (errorMessages ) 包含错误消息,您可以使用它字典键中的属性。
    • 看这取决于你的逻辑你是怎么做的。为此,您需要为按钮绑定命令。而且我现在没有代码,因为我的笔记本电脑上没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    • 2011-05-08
    相关资源
    最近更新 更多