2008-09-19 14 views
12

Estoy intentando 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.Validación WPF que no se activa en el primer LostFocus del TextBox

Aquí es 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> 

Respuesta

18

Si usted no es adversa a poner un poco de lógica en su código detrás, se puede manejar el real LostFocus evento 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(); 
} 
+0

+1 ¡Solución inteligente! –

+0

Desafortunadamente, esto se puede aplicar con la lógica MVVM. ¿Alguna pista sobre cómo hacerlo cuando no quieres modificar tu código? – FanaticD

6

Desafortunadamente 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.

Una de las cosas que puede hacer, sin embargo, es obtener la expresión de enlace de la propiedad del control e invocar manualmente las validaciones. Apesta, pero funciona.

0

He pasado por el mismo problema y he encontrado una forma 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!

+2

Gracias pero esa solución no es escalable y será difícil de mantener en todas las páginas! – azamsharp

4

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.

Se podría actualizar su elemento de unión de la siguiente manera:

<Binding 
    Source="{StaticResource CustomerKey}" 
    Path="LastName" 
    ValidatesOnExceptions="True" 
    ValidatesOnDataErrors="True" 
    UpdateSourceTrigger="LostFocus"> 
    <Binding.ValidationRules> 
     <DataErrorValidationRule 
      ValidatesOnTargetUpdated="True" /> 
    </Binding.ValidationRules> 
</Binding> 
+1

Si marca con reflector, verá que la propiedad 'ValidatesOnTargetUpdated' ya está establecida por DataErrorValidationRule en verdadero. Llama a un constructor heredado con un param que especifica esto. Por lo tanto, agregar las asignaciones de propiedades como se muestra no hará ninguna diferencia. Bueno, pensé - He estado tratando de solucionar un problema similar y esto inicialmente parecía prometedor. – Phil

+0

¡Esto funcionó para mí en una regla personalizada! ¡Gracias un millón de amigos! – JFTxJ

0

El código de seguimiento bucles sobre 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 pre validarlos para usted.

1

descubrí la mejor manera para mí de manejar esto fue en el evento LostFocus del cuadro de texto que hago algo como esto

private void dbaseNameTextBox_LostFocus(object sender, RoutedEventArgs e) 
    { 
     if (string.IsNullOrWhiteSpace(dbaseNameTextBox.Text)) 
     { 
      dbaseNameTextBox.Text = string.Empty; 
     } 
    } 

Luego se ve un error

+0

¿Es esta una respuesta o está tratando de obtener ayuda con un problema que está teniendo? – animuson

Cuestiones relacionadas