validations validate error data assist wpf validation error-handling

validate - wpf mvvm error validation



wpf combobox validate (1)

Prefiero publicar un ejemplo de validación con su modelo. Ajuste este ejemplo como lo necesite, y probablemente encontrará diferencias que producen un trabajo incorrecto.

MainWindow.xaml

<StackPanel> <TextBox x:Name="ValidatedTextBox" Width="200"> <TextBox.Text> <Binding Path="EnteredText" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> <Binding.ValidationRules> <local:NotEmptyInputRule ValidatesOnTargetUpdated="True" /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <Button Content="Save" Width="60" IsEnabled="{Binding IsValid}" /> </StackPanel>

Propiedad EnteredText debe existir en ViewModel:

class MainWindowViewModel : INotifyPropertyChanged { public ICommand SaveItem { get { return new SimpleCommand(SaveItemExecute, CanSaveItem); } } public void SaveItemExecute() { //save } private bool CanSaveItem() { return IsValid; } //I set up here a breakpoint and it returns the correct value just once. //The application looked up on CanSaveItem all the time and except the first time, it returns wrong value private bool _isValid; public bool IsValid { get { return _isValid; } set { _isValid = value; OnPropertyChanged("IsValid"); } } public string EnteredText { get; set; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }

Y no te olvides de configurar DataContext en MainWindow.

public MainWindow() { InitializeComponent(); InitializeValidaton(); this.DataContext = viewModel.Value; }

También están la clase Command y la regla de validación.

public class SimpleCommand : ICommand { /// <summary> /// Gets or sets the Predicate to execute when the CanExecute of the command gets called /// </summary> public Predicate<object> CanExecuteDelegate { get; set; } /// <summary> /// Gets or sets the action to be called when the Execute method of the command gets called /// </summary> public Action<object> ExecuteDelegate { get; set; } public SimpleCommand(Action execute, Func<bool> canExecute) { this.ExecuteDelegate = _ => execute(); this.CanExecuteDelegate = _ => canExecute(); } #region ICommand Members /// <summary> /// Checks if the command Execute method can run /// </summary> /// <param name="parameter">THe command parameter to be passed</param> /// <returns>Returns true if the command can execute. By default true is returned so that if the user of SimpleCommand does not specify a CanExecuteCommand delegate the command still executes.</returns> public bool CanExecute(object parameter) { if (CanExecuteDelegate != null) return CanExecuteDelegate(parameter); return true;// if there is no can execute default to true } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } /// <summary> /// Executes the actual command /// </summary> /// <param name="parameter">THe command parameter to be passed</param> public void Execute(object parameter) { if (ExecuteDelegate != null) ExecuteDelegate(parameter); } #endregion

}

class NotEmptyInputRule : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { if (value != null) { string input = value as string; if (input.Length > 0) return new ValidationResult(true, null); } return new ValidationResult(false, "Validation error. Field input required."); } }

Tengo una aplicación wpf simple y estoy tratando de desactivar el botón guardar si el formulario tiene errores.

El problema es que, aunque la validación parece que funciona perfectamente, no sé por qué, pero estoy obteniendo todo el tiempo falso del método que es responsable de verificar los errores.

Permítanme aclararlo proporcionando el código.

Este es el código de MainWindow.Xaml.cs

private readonly HashSet<ValidationError> errors = new HashSet<ValidationError>(); private Lazy<MainWindowViewModel> viewModel; public MainWindow() { InitializeComponent(); InitializeValidaton(); } void InitializeValidaton() { viewModel = new Lazy<MainWindowViewModel>(); Validation.AddErrorHandler(this, ErrorChangedHandler); } private void ErrorChangedHandler(object sender, ValidationErrorEventArgs e) { if (e.Action == ValidationErrorEventAction.Added) { errors.Add(e.Error); } else { errors.Remove(e.Error); } //I set a breakpoint here and it returns the correct value. False if it has errors and True if not viewModel.Value.IsValid = !errors.Any(); }

Este es el comando para el botón

public ICommand SaveItem { get { return new RelayCommand(SaveItemExecute,CanSaveItem); } } private bool CanSaveItem() { return IsValid; } //I set up here a breakpoint and it returns the correct value just once. //The application looked up on CanSaveItem all the time and except the first time, it returns wrong value private bool _isValid; public bool IsValid { get { return _isValid; } set { _isValid = value; RaisePropertyChanged("IsValid"); } }

Reglas de validación

[Required(ErrorMessage = "Please enter Title")] [StringLength(100, ErrorMessage = "The maximum length is 100")] string Name { get; set; }

No sé si tiene sentido, pero el botón que quiero desactivar está en un UserControl.

No puedo entender por qué el método canExecute, que está en un userControl, se activó más de una vez. Cualquiera que sea el método si lo usé, tiene la misma reacción. Menciono UserControl, porque si utilizo el mismo método (que en parte de ICommand) en la ventana principal, se activó solo una vez

Apreciaré si alguien pudiera ayudarme con esto.

Gracias