2008-09-19 14 views
12

Próbuję sprawdzić poprawność formularza WPF wobec obiektu. Sprawdzanie poprawności jest wywoływane, gdy wpisuję coś w polu tekstowym, w którym fokus powraca do pola tekstowego, a następnie kasuje to, co napisałem. Ale jeśli po prostu wczytam aplikację WPF i tabulator poza pole tekstowe bez pisania i usuwania niczego z pola tekstowego, to nie jest on uruchamiany.Walidacja WPF nie wypalanie na pierwszym LostFocus z TextBox

Oto klasa 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; 
      } 
     } 
    } 

A oto kod 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> 

Odpowiedz

18

Jeśli nie jesteś niekorzystne objęcia trochę logiki w kodzie tyłu, można obsługiwać rzeczywiste LostFocus zdarzenie z czymś to:

.xaml

<TextBox LostFocus="TextBox_LostFocus" .... 

.xaml.cs

private void TextBox_LostFocus(object sender, RoutedEventArgs e) 
{ 
    ((Control)sender).GetBindingExpression(TextBox.TextProperty).UpdateSource(); 
} 
+0

+1 Sprytne rozwiązanie! –

+0

Niestety można to zastosować z logiką MVVM. Jakieś wskazówki, jak to zrobić, gdy nie chcesz modyfikować swojego kodu? – FanaticD

6

Niestety to jest zgodne z projektem. Walidacja WPF uruchamia się tylko wtedy, gdy zmieniła się wartość w sterowaniu.

Niewiarygodne, ale prawdziwe. Jak dotąd, walidacja WPF to duży przysłowiowy ból - to straszne.

Jedną z rzeczy, które można wykonać, jest pobranie wyrażenia wiążącego z właściwości kontrolki i ręczne wywołanie sprawdzeń. To jest do bani, ale działa.

0

Przeszedłem przez ten sam problem i znalazłem bardzo prosty sposób rozwiązania tego problemu: w załadowanym zdarzeniu twojego okna, po prostu wstaw txtLastName.Text = String.Empty. To jest to!! Ponieważ właściwość twojego obiektu zmieniła się (została ustawiona na pusty ciąg), zwalnianie walidacji!

+2

Dzięki, ale to rozwiązanie nie jest skalowalne i będzie trudne do utrzymania na wszystkich stronach! – azamsharp

4

Zobacz właściwość ValidationRule w wersji ValidatesOnTargetUpdated. Sprawdza się, gdy dane są najpierw ładowane. Jest to dobre, jeśli próbujesz złapać puste lub puste pola.

Można by zaktualizować elementu wiążącego tak:

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

Jeśli sprawdzisz za pomocą reflektora, zobaczysz, że właściwość "ValidatesOnTargetUpdated" jest już ustawiona przez wartość DataErrorValidationRule na wartość true. Wywołuje dziedziczony konstruktor z parametrem, który to określa. Dodanie przypisań do nieruchomości, jak pokazano, nie będzie miało żadnego znaczenia. Dobra myśl - próbowałem rozwiązać podobny problem i początkowo wyglądało to obiecująco. – Phil

+0

To działało dla mnie na niestandardowej zasadzie! Dziękujemy milionowi kumplowi! – JFTxJ

0

Kod obserwacji pętli nad wszystkimi kontrolami i sprawdza je. Niekoniecznie jest to preferowany sposób, ale wydaje się działać. Robi to tylko TextBlocks i TextBox, ale możesz je łatwo zmienić.

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(); 
     } 

    } 
} 

Po prostu zadzwoń Sprawdź poprawność okna lub kontroli i powinna wstępnie je dla ciebie zatwierdzić.

1

I okazało się, że najlepszym sposobem dla mnie obsłużyć to było w przypadku LostFocus pola tekstowego I zrobić coś takiego

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

Potem widzi błąd

+0

Czy to jest odpowiedź, czy próbujesz uzyskać pomoc dotyczącą problemu, który masz? – animuson