为WPF TextBox实现验证

33 浏览
0 Comments

为WPF TextBox实现验证

我有3个文本框(Id1NameSalary)。IdSalary应该包含整数,Name应该只包含字符。我需要对我的文本框进行验证,当我输入错误的字符或整数时,它应该显示错误。还可以在没有代码后台的情况下仅在Xaml中完成吗?请帮我提供所需的代码

这是Xaml代码:


admin 更改状态以发布 2023年5月24日
0
0 Comments

您还可以在视图模型中实现IDataErrorInfo。 如果您实现了 IDataErrorInfo ,则可以在其中进行验证,而不是在特定属性的setter中进行验证,然后每当出现错误时,返回错误消息,以便具有错误的文本框周围出现红框,表示错误。

class ViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    private string m_Name = "Type Here";
    public ViewModel()
    {
    }
    public string Name
    {
        get
        {
            return m_Name;
        }
        set
        {
            if (m_Name != value)
            {
                m_Name = value;
                OnPropertyChanged("Name");
            }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public string Error
    {
        get { return "...."; }
    }
    /// 
    /// Will be called for each and every property when ever its value is changed
    /// 
    /// Name of the property whose value is changed
    /// 
    public string this[string columnName]
    {
        get 
        {
            return Validate(columnName);
        }
    }
    private string Validate(string propertyName)
    {
        // Return error message if there is error on else return empty or null string
        string validationMessage = string.Empty;
        switch (propertyName)
        {
            case "Name": // property name
                // TODO: Check validiation condition
                validationMessage = "Error";
                break;
        }
        return validationMessage;
    }
}

并且您必须在XAML中设置 ValidatesOnDataErrors=True ,以便调用如下IDataErrorInfo 的方法:


0
0 Comments

实施验证的3种方法:

  1. 验证规则
  2. INotifyDataErrorInfo实现
  3. IDataErrorInfo实现

验证规则示例

public class NumericValidationRule : ValidationRule
{
    public Type ValidationType { get; set; }
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        string strValue = Convert.ToString(value);
        if (string.IsNullOrEmpty(strValue))
            return new ValidationResult(false, $"Value cannot be coverted to string.");
        bool canConvert = false;
        switch (ValidationType.Name)
        {
            case "Boolean":
                bool boolVal = false;
                canConvert = bool.TryParse(strValue, out boolVal);
                return canConvert ? new ValidationResult(true, null) : new ValidationResult(false, $"Input should be type of boolean");
            case "Int32":
                int intVal = 0;
                canConvert = int.TryParse(strValue, out intVal);
                return canConvert ? new ValidationResult(true, null) : new ValidationResult(false, $"Input should be type of Int32");
            case "Double":
                double doubleVal = 0;
                canConvert = double.TryParse(strValue, out doubleVal);
                return canConvert ? new ValidationResult(true, null) : new ValidationResult(false, $"Input should be type of Double");
            case "Int64":
                long longVal = 0;
                canConvert = long.TryParse(strValue, out longVal);
                return canConvert ? new ValidationResult(true, null) : new ValidationResult(false, $"Input should be type of Int64");
            default:
                throw new InvalidCastException($"{ValidationType.Name} is not supported");
        }
    }
}

XAML:

非常重要:不要忘记设置ValidatesOnTargetUpdated="True",否则它将不起作用。

 
    
    
        
            
                
            
        
    
    

INotifyDataErrorInfo示例

public abstract class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
{
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        ValidateAsync();
    }
    #endregion
    public virtual void OnLoaded()
    {
    }
    #region INotifyDataErrorInfo
    private ConcurrentDictionary> _errors = new ConcurrentDictionary>();
    public event EventHandler ErrorsChanged;
    public void OnErrorsChanged(string propertyName)
    {
        var handler = ErrorsChanged;
        if (handler != null)
            handler(this, new DataErrorsChangedEventArgs(propertyName));
    }
    public IEnumerable GetErrors(string propertyName)
    {
        List errorsForName;
        _errors.TryGetValue(propertyName, out errorsForName);
        return errorsForName;
    }
    public bool HasErrors
    {
        get { return _errors.Any(kv => kv.Value != null && kv.Value.Count > 0); }
    }
    public Task ValidateAsync()
    {
        return Task.Run(() => Validate());
    }
    private object _lock = new object();
    public void Validate()
    {
        lock (_lock)
        {
            var validationContext = new ValidationContext(this, null, null);
            var validationResults = new List();
            Validator.TryValidateObject(this, validationContext, validationResults, true);
            foreach (var kv in _errors.ToList())
            {
                if (validationResults.All(r => r.MemberNames.All(m => m != kv.Key)))
                {
                    List outLi;
                    _errors.TryRemove(kv.Key, out outLi);
                    OnErrorsChanged(kv.Key);
                }
            }
            var q = from r in validationResults
                    from m in r.MemberNames
                    group r by m into g
                    select g;
            foreach (var prop in q)
            {
                var messages = prop.Select(r => r.ErrorMessage).ToList();
                if (_errors.ContainsKey(prop.Key))
                {
                    List outLi;
                    _errors.TryRemove(prop.Key, out outLi);
                }
                _errors.TryAdd(prop.Key, messages);
                OnErrorsChanged(prop.Key);
            }
        }
    }
    #endregion
}

视图模型实现:

public class MainFeedViewModel : BaseViewModel//, IDataErrorInfo
{
    private ObservableCollection _feedItems;
    [XmlIgnore]
    public ObservableCollection FeedItems
    {
        get
        {
            return _feedItems;
        }
        set
        {
            _feedItems = value;
            OnPropertyChanged("FeedItems");
        }
    }
    [XmlIgnore]
    public ObservableCollection FilteredFeedItems
    {
        get
        {
            if (SearchText == null) return _feedItems;
            return new ObservableCollection(_feedItems.Where(x => x.Title.ToUpper().Contains(SearchText.ToUpper())));
        }
    }
    private string _title;
    [Required]
    [StringLength(20)]
    //[CustomNameValidationRegularExpression(5, 20)]
    [CustomNameValidationAttribute(3, 20)]
    public string Title
    {
        get { return _title; }
        set
        {
            _title = value;
            OnPropertyChanged("Title");
        }
    }
    private string _url;
    [Required]
    [StringLength(200)]
    [Url]
    //[CustomValidation(typeof(MainFeedViewModel), "UrlValidation")]
    /// 
    /// Validation of URL should be with custom method like the one that implemented below, or with 
    /// 
    public string Url
    {
        get { return _url; }
        set
        {
            _url = value;
            OnPropertyChanged("Url");
        }
    }
    public MainFeedViewModel(string url, string title)
    {
        Title = title;
        Url = url;
    }
    /// 
    /// 
    /// 
    public MainFeedViewModel()
    {
    }
    public MainFeedViewModel(ObservableCollection feeds)
    {
        _feedItems = feeds;
    }
    private string _searchText;
    [XmlIgnore]
    public string SearchText
    {
        get { return _searchText; }
        set
        {
            _searchText = value;
            OnPropertyChanged("SearchText");
            OnPropertyChanged("FilteredFeedItems");
        }
    }
    #region Data validation local
    /// 
    /// Custom URL validation method
    /// 
    /// 
    /// 
    /// 
    public static ValidationResult UrlValidation(object obj, ValidationContext context)
    {
        var vm = (MainFeedViewModel)context.ObjectInstance;
        if (!Uri.IsWellFormedUriString(vm.Url, UriKind.Absolute))
        {
            return new ValidationResult("URL should be in valid format", new List { "Url" });
        }
        return ValidationResult.Success;
    }
    #endregion
}

XAML:


    
        
        
    
    
        
            
            
            
        
        
            
            
            
            
            
        
        
        
        
        
    

IDataErrorInfo

视图模型:

public class OperationViewModel : ViewModelBase, IDataErrorInfo
{
    private const int ConstCodeMinValue = 1;
    private readonly IEventAggregator _eventAggregator;
    private OperationInfoDefinition _operation;
    private readonly IEntityFilterer _contextFilterer;
    private OperationDescriptionViewModel _description;
    public long Code
    {
        get { return _operation.Code; }
        set
        {
            if (SetProperty(value, _operation.Code, o => _operation.Code = o))
            {
                UpdateDescription();
            }
        }
    }
    public string Description
    {
        get { return _operation.Description; }
        set
        {
            if (SetProperty(value, _operation.Description, o => _operation.Description = o))
            {
                UpdateDescription();
            }
        }
    }
    public string FriendlyName
    {
        get { return _operation.FriendlyName; }
        set
        {
            if (SetProperty(value, _operation.FriendlyName, o => _operation.FriendlyName = o))
            {
                UpdateDescription();
            }
        }
    }
    public int Timeout
    {
        get { return _operation.Timeout; }
        set
        {
            if (SetProperty(value, _operation.Timeout, o => _operation.Timeout = o))
            {
                UpdateDescription();
            }
        }
    }
    public string Category
    {
        get { return _operation.Category; }
        set
        {
            if (SetProperty(value, _operation.Category, o => _operation.Category = o))
            {
                UpdateDescription();
            }
        }
    }
    public bool IsManual
    {
        get { return _operation.IsManual; }
        set
        {
            if (SetProperty(value, _operation.IsManual, o => _operation.IsManual = o))
            {
                UpdateDescription();
            }
        }
    }
    void UpdateDescription()
    {
        //some code
    }
    #region Validation
    #region IDataErrorInfo
    public ValidationResult Validate()
    {
        return ValidationService.Instance.ValidateNumber(Code, ConstCodeMinValue, long.MaxValue);
    }
    public string this[string columnName]
    {
        get
        {
            var validation = ValidationService.Instance.ValidateNumber(Code, ConstCodeMinValue, long.MaxValue);
            return validation.IsValid ? null : validation.ErrorContent.ToString();
        }
    }
    public string Error
    {
        get
        {
            var result = Validate();
            return result.IsValid ? null : result.ErrorContent.ToString();
        }
    }
    #endregion
    #endregion
}

XAML:


    
        
            
            
        
        
            
            
            
            
            
            
            
            
            
        
        
        
        
        
        
        
        
        
        
        
        
        
    

0