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);
}
}
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 validar B
(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.
OnPropertyChanged(nameof(B))
al setter de aA
(y el equivalente para el setter deB
)?