wpf - studio - ¿Cómo puedo validar múltiples propiedades cuando alguna de ellas cambia?
visual studio installer (4)
Tengo dos campos de fecha: StartDate y EndDate. StartDate debe ser anterior a EndDate.
Si el usuario cambia la fecha de inicio a algo mayor que la fecha de finalización, aparece un borde rojo alrededor de ese DatePicker y viceversa. Si el usuario cambia el segundo cuadro para que el intervalo de fechas ahora sea correcto, el primer cuadro todavía tiene el error de validación.
¿Cómo puedo validar ambos campos de fecha cuando uno de ellos cambia?
Estoy usando IDataErrorInfo
public string GetValidationError(string propertyName)
{
switch (propertyName)
{
case "StartDate":
if (StartDate > EndDate)
s = "Start Date cannot be later than End Date";
break;
case "EndDate":
if (StartDate > EndDate)
s = "End Date cannot be earlier than Start Date";
break;
}
return s;
}
No puedo simplemente generar un evento PropertyChange porque necesito validar ambos campos cuando alguno de ellos cambia, por lo que al hacer que ambos generen un evento PropertyChange, el otro se quedará atascado en un bucle infinito.
Tampoco me gusta la idea de borrar el campo Fecha si la otra fecha devuelve un error de validación.
Generalmente agrego todos mis errores de validación a un diccionario, y tengo la plantilla de validación suscrita a través del nombre de la propiedad. En cada controlador de evento de propiedad cambiado, puedo verificar cualquier número de propiedades y agregar o eliminar su estado de validación según sea necesario.
Compruebe esta respuesta para ver cómo se ve mi implementación. Lo siento está en VB.NET, pero debería ser bastante sencillo.
La forma más sencilla es elevar una notificación de PropertyChanged
en el configurador para ambas propiedades que deben validarse como sugiere Bathineni.
private DateTime StartDate
{
get { return _startDate; }
set
{
if (_startDate != value)
{
_startDate = value;
RaisePropertyChanged("StartDate");
RaisePropertyChanged("EndDate");
}
}
}
private DateTime EndDate
{
get { return _endDate; }
set
{
if (_endDate!= value)
{
_endDate= value;
RaisePropertyChanged("StartDate");
RaisePropertyChanged("EndDate");
}
}
}
Sin embargo, si eso no funciona para usted, descubrí una forma de validar un grupo de propiedades, aunque sus clases tienen que implementar INotifyPropertyChanging
además de INotifyPropertyChanged
(estoy usando EntityFramework y, por defecto, sus clases implementan ambas interfaces)
Método de extensión
public static class ValidationGroup
{
public delegate string ValidationDelegate(string propertyName);
public delegate void PropertyChangedDelegate(string propertyName);
public static void AddValidationGroup<T>(this T obj,
List<string> validationGroup, bool validationFlag,
ValidationDelegate validationDelegate,
PropertyChangedDelegate propertyChangedDelegate)
where T : INotifyPropertyChanged, INotifyPropertyChanging
{
// This delegate runs before a PropertyChanged event. If the property
// being changed exists within the Validation Group, check for validation
// errors on the other fields in the group. If there is an error with one
// of them, set a flag to true.
obj.PropertyChanging += delegate(object sender, PropertyChangingEventArgs e)
{
if (validationGroup.Contains(e.PropertyName))
{
foreach(var property in validationGroup)
{
if (validationDelegate(property) != null)
{
validationFlag = true;
break;
}
}
}
};
// After the Property gets changed, if another field in this group was
// invalid prior to the change, then raise the PropertyChanged event for
// all other fields in the Validation Group to update them.
// Also turn flag off so it doesn''t get stuck in an infinite loop
obj.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
if (validationGroup.Contains(e.PropertyName))
{
if (validationFlag && validationDelegate(e.PropertyName) == null)
{
validationFlag = false;
foreach(var property in validationGroup)
{
propertyChangedDelegate(property);
}
}
}
};
}
}
Para usarlo, agregue la siguiente llamada al constructor de cualquier clase que debe validar un grupo de propiedades en conjunto.
this.AddValidationGroup(
new List<string> { "StartDate", "EndDate" },
GetValidationError, OnPropertyChanged);
He probado esto con hasta 3 propiedades en un grupo de validación y parece funcionar bien.
También puede suscribirse al controlador de eventos SelectedDateChanged y actualizar el enlace necesario.
BindingExpression expression = datePickerStartDate.GetBindingExpression(DatePicker.SelectedDateProperty);
if (expression != null)
{
expression.UpdateSource();
}
Usa este truco, evita que se llamen OnPropertyChanged entre sí:
private bool RPCfromStartDate = false;
private bool RPCfromEndDate = false;
public string this[string columnName]
{
get
{
string result = null;
switch (columnName)
{
case "StartDate":
if (StartDate.Date >= EndDate.Date)
{
result = "Start Date cannot be later than End Date";
}
if (!RPCfromEndDate)
{
RPCfromStartDate = true;
OnPropertyChanged("EndDate");
RPCfromStartDate = false;
}
case "EndDate":
if (StartDate.Date >= EndDate.Date)
{
result = "End Date cannot be earlier than Start Date";
}
if (!RPCfromStartDate)
{
RPCfromEndDate = true;
OnPropertyChanged("StartDate");
RPCfromEndDate = false;
}
break;
}
...