vacios - La validación WPF no se activa en el primer LostFocus del TextBox
validar textbox c# (6)
Estoy tratando de validar el formulario WPF contra un objeto. La validación se dispara cuando escribo algo en el recuadro de texto pierdo el foco vuelve al cuadro de texto y luego borro todo lo que he escrito. Pero si solo carga la aplicación WPF y la pestaña del cuadro de texto sin escribir y borrar nada del cuadro de texto, entonces no se dispara.
Aquí está la clase Customer.cs:
public class Customer : IDataErrorInfo
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Error
{
get { throw new NotImplementedException(); }
}
public string this[string columnName]
{
get
{
string result = null;
if (columnName.Equals("FirstName"))
{
if (String.IsNullOrEmpty(FirstName))
{
result = "FirstName cannot be null or empty";
}
}
else if (columnName.Equals("LastName"))
{
if (String.IsNullOrEmpty(LastName))
{
result = "LastName cannot be null or empty";
}
}
return result;
}
}
}
Y aquí está el código de WPF:
<TextBlock Grid.Row="1" Margin="10" Grid.Column="0">LastName</TextBlock>
<TextBox Style="{StaticResource textBoxStyle}" Name="txtLastName" Margin="10"
VerticalAlignment="Top" Grid.Row="1" Grid.Column="1">
<Binding Source="{StaticResource CustomerKey}" Path="LastName"
ValidatesOnExceptions="True" ValidatesOnDataErrors="True"
UpdateSourceTrigger="LostFocus"/>
</TextBox>
Descubrí que la mejor manera de manejar esto era en el evento LostFocus del cuadro de texto. Hice algo como esto
private void dbaseNameTextBox_LostFocus(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(dbaseNameTextBox.Text))
{
dbaseNameTextBox.Text = string.Empty;
}
}
Luego ve un error
Lamentablemente esto es por diseño. La validación de WPF solo se activa si el valor en el control ha cambiado.
Increíble, pero cierto. Hasta ahora, la validación WPF es el gran dolor proverbial, es terrible.
Sin embargo, una de las cosas que puede hacer es obtener la expresión vinculante de la propiedad del control e invocar manualmente las validaciones. Apesta, pero funciona.
He pasado por el mismo problema y encontré una manera muy simple de resolver esto: en el evento Loaded de su ventana, simplemente ponga txtLastName.Text = String.Empty. ¡¡Eso es!! Como la propiedad de su objeto ha cambiado (se ha establecido en una cadena vacía), ¡la activación de la validación!
Eche un vistazo a la propiedad ValidatesOnTargetUpdated de ValidationRule. Validará cuando los datos se carguen por primera vez. Esto es bueno si intenta atrapar campos vacíos o nulos.
Actualizarías tu elemento de enlace así:
<Binding
Source="{StaticResource CustomerKey}"
Path="LastName"
ValidatesOnExceptions="True"
ValidatesOnDataErrors="True"
UpdateSourceTrigger="LostFocus">
<Binding.ValidationRules>
<DataErrorValidationRule
ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
Si no está en contra de poner un poco de lógica en su código, puede manejar el evento LostFocus real con algo como esto:
.xaml
<TextBox LostFocus="TextBox_LostFocus" ....
.xaml.cs
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
((Control)sender).GetBindingExpression(TextBox.TextProperty).UpdateSource();
}
El siguiente código recorre todos los controles y los valida. No necesariamente la forma preferida, pero parece funcionar. Solo funciona con TextBlocks y TextBoxes, pero puedes cambiarlo fácilmente.
public static class PreValidation
{
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
public static void Validate(DependencyObject depObj)
{
foreach(var c in FindVisualChildren<FrameworkElement>(depObj))
{
DependencyProperty p = null;
if (c is TextBlock)
p = TextBlock.TextProperty;
else if (c is TextBox)
p = TextBox.TextProperty;
if (p != null && c.GetBindingExpression(p) != null) c.GetBindingExpression(p).UpdateSource();
}
}
}
Simplemente llame a Validate en su ventana o control y debe prevalidarlos por usted.