WPF TextBox Validation C #

Tengo 3 TextBoxes ( Id1 , Name y Salary ). Id y Salary deben contener números enteros y Name solo debe contener caracteres. Necesito validaciones para mi TextBox, debería mostrar errores a medida que ingreso caracteres o enteros incorrectos. ¿También se puede hacer esto solo en Xaml sin código detrás? Soy nuevo en Wpf y la validación por favor ayúdenme con el código requerido

Este es el código Xaml:

    

Hay 3 formas de implementar la validación:

  1. Regla de validación
  2. Implementación de INotifyDataErrorInfo
  3. Implementación de IDataErrorInfo

Ejemplo de regla de validación :

 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:

Muy importante : no te olvides de configurar ValidatesOnTargetUpdated="True" , no funcionará sin esta definición.

             

Ejemplo de 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 } 

Ver implementación del modelo:

 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 :

Ver modelo:

 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:

                                

También puede implementar IDataErrorInfo siguiente manera en el modelo de vista. Si implementa IDataErrorInfo , puede hacer la validación en lugar del setter de una propiedad en particular, y siempre que haya un error, devuelva un mensaje de error para que el cuadro de texto que tiene el error obtenga un cuadro rojo a su alrededor, lo que indica error.

 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; } } 

Y debe establecer ValidatesOnDataErrors=True en XAML para invocar los métodos de IDataErrorInfo siguiente manera:

  

Para hacerlo solo con XAML, debe agregar Reglas de Validación para propiedades individuales. Pero te recomendaría ir con código detrás de enfoque. En su código, defina sus especificaciones en los ajustadores de propiedades y aplique excepciones cuando no cumpla con sus especificaciones. Y use la plantilla de error para mostrar sus errores al usuario en la interfaz de usuario. Tu XAML se verá así

        

Código detrás:

 public partial class MainWindow : Window { private ExampleViewModel m_ViewModel; public MainWindow() { InitializeComponent(); m_ViewModel = new ExampleViewModel(); DataContext = m_ViewModel; } } public class ExampleViewModel : INotifyPropertyChanged { private string m_Name = "Type Here"; public ExampleViewModel() { } public string Name { get { return m_Name; } set { if (String.IsNullOrEmpty(value)) { throw new Exception("Name can not be empty."); } if (value.Length > 12) { throw new Exception("name can not be longer than 12 charectors"); } 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)); } } } 

Implementé esta validación Pero se usaría código detrás. Es demasiado fácil y la manera más simple.

XAML: para la Validación de nombre solo ingrese el carácter de AZ y az.

   

Código detrás.

 private void first_name_texbox_PreviewTextInput ( object sender, TextCompositionEventArgs e ) { Regex regex = new Regex ( "[^a-zA-Z]+" ); if ( regex.IsMatch ( first_name_texbox.Text ) ) { MessageBox.Show("Invalid Input !"); } } 

Para la validación de Salario e ID, reemplace el valor pasado del constructor de expresiones regulares por [0-9]+ . Significa que solo puede ingresar el número de 1 a infinito.

También puede definir la longitud con [0-9]{1,4} . Significa que solo puede ingresar menos o igual a un número de 4 dígitos. Esta baracket significa {al menos, ¿cuántos número}. Al hacer esto, puede definir el rango de números en el cuadro de texto.

Puede ayudar a otros.

XAML:

Código detrás.

 private void salary_texbox_PreviewTextInput ( object sender, TextCompositionEventArgs e ) { Regex regex = new Regex ( "[^0-9]+" ); if ( regex.IsMatch ( salary_texbox.Text ) ) { MessageBox.Show("Invalid Input !"); } } 

Cuando se trata de la respuesta de Muhammad Mehdi, es mejor hacer:

 private void salary_texbox_PreviewTextInput(object sender, TextCompositionEventArgs e) { Regex regex = new Regex ( "[^0-9]+" ); if(regex.IsMatch(e.Text)) { MessageBox.Show("Error"); } } 

Porque cuando se compara con TextCompositionEventArgs también obtiene el último carácter, mientras que con el cuadro de texto. Texto no. Con el cuadro de texto, el error se mostrará después del siguiente carácter insertado.