Tengo un modelo de vista con 2 propiedades: A
y B
quiero validar eso A < B
.
A continuación se muestra mi implementación simplificada donde uso la regla de validación personalizada. Dado que cada propiedad se valida de forma independiente, conduce a un problema molesto: si el A
valor ingresado no es válido, entonces permanece así incluso después de cambiar B
, ya que la validación de B
no sabe nada A
.
Esto se puede ver en esta demostración:
A
es inválido después de ingresar 11
, eso es correcto desde entonces 11 > 2
. Cambiar B
a 22
no volver a evaluar A
, tengo que editar A
para que se apruebe la validación.
¿Lo que quiero? Quiero que después de entrar 22
en B
el borde rojo (error de validación) desaparezca y A = 11, B = 22
que sean valores de origen en el modelo de vista.
¿Cómo puedo en la B
validación forzar de alguna manera la A
validación después de que el nuevo B
valor se sincronice con la fuente?
Ver modelo:
public class ViewModel : INotifyPropertyChanged
{
int _a;
public int A
{
get => _a;
set
{
_a = value;
OnPropertyChanged();
}
}
int _b;
public int B
{
get => _b;
set
{
_b = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged([CallerMemberName] string property = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
Ver:
<StackPanel>
<TextBox Margin="10" Text="{local:MyBinding A}" />
<TextBox Margin="10" Text="{local:MyBinding B}" />
</StackPanel>
Ver código:
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel { A = 1, B = 2 };
}
Unión:
public class MyBinding : Binding
{
public MyBinding(string path) : base(path)
{
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
ValidationRules.Add(new MyValidationRule());
}
}
Regla de validación:
public class MyValidationRule : ValidationRule
{
public MyValidationRule() : base(ValidationStep.ConvertedProposedValue, false) { }
public override ValidationResult Validate(object value, CultureInfo cultureInfo) => ValidationResult.ValidResult; // not used
public override ValidationResult Validate(object value, CultureInfo cultureInfo, BindingExpressionBase owner)
{
var binding = owner as BindingExpression;
var vm = binding?.DataItem as ViewModel;
switch (binding.ResolvedSourcePropertyName)
{
case nameof(vm.A):
if ((int)value >= vm.B)
return new ValidationResult(false, "A should be smaller than B");
break;
case nameof(vm.B):
if ((int)value <= vm.A)
return new ValidationResult(false, "B should be bigger than A");
break;
}
return base.Validate(value, cultureInfo, owner);
}
}
fuente
OnPropertyChanged(nameof(B))
al setter de aA
(y el equivalente para el setter deB
)?INotifyDataErrorInfo
en su modelo de vista si desea realizar este tipo de validación. No es compatible con las reglas de validación.A
: antes o después de validarB
(en otras palabras, antes de que el valor de B sea aceptado y sincronizado con la fuente o después). El orden importa. Y, de hecho, primero tengo que tener todos los valores modificados a mano y solo entonces hacer la validación en orden normal.Respuestas:
ValidationRules
no admite la invalidación de una propiedad al configurar otra propiedad.Lo que debe hacer es implementar
INotifyDataErrorInfo
en su modelo de vista y generar elErrorsChanged
evento cada vez que desee actualizar el estado de validación de una propiedad.Hay un ejemplo disponible en este artículo de TechNet .
fuente