2012-03-21 17 views
11

Todavía estoy luchando con la validación en WPF.Encuadernación de validación en la primera carga

Tengo una regla de validación personalizada que requiere que el texto aparezca en un cuadro de texto, es decir, impone una restricción de campo obligatorio.

<TextBox local:Masking.Mask="^[a-zA-Z0-9]*$" x:Name="CameraIdCodeTextBox" Grid.Row="1" Grid.Column="1"> 
    <Binding Path="CameraIdCode" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True" ValidatesOnExceptions="True"> 
    <Binding.ValidationRules> 
     <localValidation:RequiredFieldRule /> 
    </Binding.ValidationRules> 
    </Binding> 
</TextBox> 

El problema es que cuando las primeras cargas de la ventana, no hay texto en el cuadro de texto (como era de esperar). Pero la propiedad Text está vinculada a una propiedad en ViewModel y, como tal, la Regla de validación está activa, lo que indica que hay un problema con la Ventana, antes de que el usuario haya tenido la oportunidad de infringir una regla comercial.

¿Es esto un problema que ha sido resuelto antes? No pude haber sido el primero en experimentar esto. Estoy seguro de que es una trampa para jugadores jóvenes.

+0

Puede intentar ... UpdateSourceTrigger = "LostFocus" –

+0

Puede crear un grupo de validación, y solo habilitarlo, cuando el usuario hace un cambio en algún campo por primera vez. –

+0

@AngelWPF Lo he intentado. Todavía valida en el enlace inicial cuando se carga la ventana. – onefootswill

Respuesta

0

Ha sido un tiempo y debería haber actualizado esta pregunta. Resolví usando una clase que he encontrado en un libro WPF por Ian Griffths (un libro de O'Reilly):

public static class Validator 
{ 
    /// <summary> 
    /// This method forces WPF to validate the child controls of the control passed in as a parameter. 
    /// </summary> 
    /// <param name="parent">Type: DependencyObject. The control which is the descendent root control to validate.</param> 
    /// <returns>Type: bool. The validation result</returns> 
    public static bool IsValid(DependencyObject parent) 
    { 
     // Validate all the bindings on the parent 
     bool valid = true; 
     LocalValueEnumerator localValues = parent.GetLocalValueEnumerator(); 
     while (localValues.MoveNext()) 
     { 
      LocalValueEntry entry = localValues.Current; 
      if (BindingOperations.IsDataBound(parent, entry.Property)) 
      { 
       Binding binding = BindingOperations.GetBinding(parent, entry.Property); 
       foreach (ValidationRule rule in binding.ValidationRules) 
       { 
        ValidationResult result = rule.Validate(parent.GetValue(entry.Property), null); 
        if (!result.IsValid) 
        { 
         BindingExpression expression = BindingOperations.GetBindingExpression(parent, entry.Property); 
         Validation.MarkInvalid(expression, new ValidationError(rule, expression, result.ErrorContent, null)); 
         valid = false; 
        } 
       } 
      } 
     } 

     // Validate all the bindings on the children 
     for (int i = 0; i != VisualTreeHelper.GetChildrenCount(parent); ++i) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(parent, i); 
      if (!IsValid(child)) 
      { 
       valid = false; 
      } 
     } 

     return valid; 
    } 

} 

continuación, en la vista, que tenía la siguiente configuración:

<TextBox local:Masking.Mask="^[0-9]*$" IsEnabled="{Binding Path=LocationNumberEnabled}" Grid.Row="1" Grid.Column="3"> 
    <Binding Path="LocationNumber" Mode="TwoWay" UpdateSourceTrigger="LostFocus" NotifyOnValidationError="True" ValidatesOnExceptions="True"> 
     <Binding.ValidationRules> 
      <localValidation:PositiveNumberRule /> 
      <localValidation:RequiredFieldRule /> 
     </Binding.ValidationRules> 
    </Binding>      
</TextBox> 

¡Trabajado como un encanto! Acabo de llamar al método IsValid cada vez que quería validar manualmente, p. en un botón presiona.

0

Hay un par de patrones para esto. Normalmente implemento en la clase/Modelo la interfaz ISupportInitialize, que requerirá que cree BeginInit() y EndInit() en esos métodos. Simplemente configuro un bool privado _isInitializing en verdadero o falso.

En el modelo de vista o donde/cuando se crea/rellenar el modelo/clase envolverlo con begin e init final:

var o = new SampleObject(); 
o.BeginInit() 
o.StartDate = DateTime.Now; //just some sample property... 
o.EndInit(); 

Así que dependiendo de cómo se invoca su ReglaDeValidación, se puede comprobar el estado de su _isInitializing para ver si necesita validar.

Últimamente he estado usando atributo de los validadores de que el fuego en PropertyChanged por lo que podría hacer algo como:

[CustomValidator("ValidateStartDate")] 
public DateTime StartDate 
{ get ... 
{ 
    set 
    { 
     if(_startDate == value) return; 
     _startDate = value; 
     if(_isInitializing) return; 
     RaisePropertyChange(() => StartDate); 
     }.. 

Si no quiere preocuparse por ISupportInitialize, a continuación, pasar todos los valores que se precisan en sus propiedades durante la construcción no son propiedad. Vinculante consultará los captadores de propiedades que por primera vez y recibirá sus valores, y después de todo lo pasará a través de la moda y ser validado propiedad:

//c-tor 
public MyObject(DateTime start) 
{ 
    _startDate = start; 
} 
Cuestiones relacionadas