2012-03-21 15 views
11

Nadal borykam się z walidacją w WPF.Wiązanie sprawdzania poprawności przy pierwszym obciążeniu

Mam niestandardową regułę sprawdzania poprawności, która wymaga pojawienia się tekstu w polu tekstowym, tj. Wymusza obowiązkowe ograniczenie pola.

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

Problem polega na tym, że po pierwszym załadowaniu okna nie ma tekstu w polu tekstowym (jak można się spodziewać). Ale właściwość Text jest powiązana z właściwością w ViewModel i jako taka uruchamia się Reguła sprawdzania poprawności, co oznacza, że ​​wystąpił problem z Oknem - zanim użytkownik miał nawet możliwość naruszenia reguły biznesowej.

Czy to był problem, który został rozwiązany wcześniej? Nie mogłem tego pierwszy doświadczać. Jestem pewien, że to pułapka dla młodych graczy.

+0

Czy możesz spróbować ... UpdateSourceTrigger = "LostFocus" –

+0

Możesz być w stanie utworzyć grupę walidacji i włączyć ją tylko wtedy, gdy użytkownik po raz pierwszy wprowadzi zmianę w pewnym polu. –

+0

@AngelWPF Próbowałem tego. Wciąż sprawdza poprawność początkowego powiązania podczas ładowania okna. – onefootswill

Odpowiedz

0

Minęło trochę czasu i powinienem był aktualizowany na to pytanie. Postanowiłem go za pomocą klasy, które znalazłem w książce WPF Ian Griffths (książka 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; 
    } 

} 

Następnie, na widoku, miałem następującą konfigurację:

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

Pracował jak urok! Właśnie nazwałem metodę IsValid za każdym razem, gdy chciałem ręcznie sprawdzić poprawność np. na naciśnięciu przycisku.

0

Istnieje kilka wzorców do tego. Zwykle implementuję interfejs klasy/modelu w interfejsie ISupportInitialize, który wymaga utworzenia BeginInit() i EndInit() w tych metodach. Po prostu ustawię wartość prywatną bool _isInitializing na wartość true lub false.

W modelu widoku lub gdzie/kiedy tworzyć/wypełnić model/klasa zawijania z nim zaczynać i kończyć startowych:

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

Tak więc w zależności jaki sposób ValidationRule jest wywoływany, można sprawdzić stan Twój numer _isInitializing, aby sprawdzić, czy musisz sprawdzić poprawność.

Ostatnio używam atrybut Walidatory których ogień na PropertyChanged więc można zrobić coś takiego:

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

Jeśli nie chcą zajmować się ISupportInitialize, a następnie przekazać wszystkie wartości, które trzeba w Twoje nieruchomości w trakcie budowy nie nieruchomości. Wiążący będzie kwerendy pobierające Ci Właściwości raz pierwszy i dostanie swoje wartości i po cokolwiek przejdzie własności setter i dostać zatwierdzone:

//c-tor 
public MyObject(DateTime start) 
{ 
    _startDate = start; 
} 
Powiązane problemy