niedziela, 16 grudnia 2012

70-511 Rozdział 6 - Binding - Walidacja

Walidacja danych ma na celu ograniczenie wprowadzania przez użytkownika nieprawidłowych danych i komunikacja nieprawidłowości na bieżąco.
WPF umożliwia zdefiniowanie zasad, walidacji danej właściwości. każda taka zasada to implementacja klasy ValidationRule:

Code:
namespace WpfExample
{
    public class IsIntValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, System.GlobalizationCultureInfo cultureInfo)
        {
            if (value == null)
            {
                return new ValidationResult(false, "Wartość nie może być nullem");
            }
            var valueAsString = value.ToString();
            int valueInt;
            if (int.TryParse(valueAsString, out valueInt))
            {
                return ValidationResult.ValidResult;
            }

            return new ValidationResult(false, "Brak możliwości konwersji na int");
        }
    }
}

Code:
<Window x:Class="WpfExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfExample"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="100">
            <TextBox.Text>
                <Binding Path="Value">
                    <Binding.ValidationRules>
                        <local:IsIntValidationRule/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <Button Content="Button" HorizontalAlignment="Left" Margin="161,128,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>

Przetwarzanie zasad następuje w kolejności w której zostały one zdefiniowane w kodzie XAML. Jeżeli walidacja przebiegnie pomyślnie, nic nadzwyczajnego nie dzieje się i interfejs programu nie zmienia zachowania. W przypadku gdy któraś z reguł nie przejdzie:
  • element, którego walidacja nie przeszła zostaje otoczony czerwoną ramką
  • zostaje ustawiona falga Validaton.HasError
  • do kolekcji Errors zostaje dodany nowy obiekt typu ValidationError
  • jeżeli jest ustawiona flaga Binding.NotifyOnValidationError - zdarzenie Validation.Error zostaje wywołane
  • zbindowana właściwość w źródle nie zostanie zaktualizowana
 Implementacja tego rozwiązania jest bardzo prosta i zgodnie z przedstawionym przykładem powyżej wymaga:
  • stworzenie klasy która dziedziczy po ValidationRule
  • nadpisujemy metodę Validate

Metoda Validate przyjmuje jako parametr wartość obiektu do walidacji i zwraca obiekt klasy ValidationResult, który posiada następujące właściwości:
  • IsValid - flaga informująca czy walidacja przebiegła pomyślnie
  • ErrorContent - informacje o błędzie w przypadku gdy walidacja nie przebiegła pomyślnie
Jeżeli chcemy sprawdzić czy walidacja zawiodła z powodu problemów z bindowaniem, możemy skorzystać z gotowej zasady ExceptionValidationRule.



Obsługa błędów walidacji
Błędy w walidacji należy obsłużyć. Czerwona obwódka wokół błędnie wprowadzonej wartości może być nie wystarczająca dla użytkownika.
Jeżeli element, który jest zbindowany ma włączoną walidację, w przypadku błędu zostanie wywołane zdarzenie Validation.Error. Zdarzenie to jako jeden z parametrów przyjmuje obiekt klasy ValidationErrorEventArgs. Klasa ta zawiera dwie ważne właściwości:
  • Action - flaga mówiąca czy zdarzenie jest wywoływane dla nowego błędu, czy też podczas usuwania starego
  • Error - opis błędu
Obiekt Error zawiera następujące informacje o błędzie:
  • BindingInError - referencja do bindingu który wywołał błąd
  • ErrorContent - opis pochodzący z obiektu ValidationRule
  • Exception
  • RuleInError - referencja do obiektu ValidationRule, który spowodował błąd
Aby zdarzenie Validation.Error było wywołane, należy ustawić flagę NotifyOnValidationError. Zdarzenie to jest typu bubbling, zapoczątkowane jest więc w elemencie którego dotyczy, a następnie przechodzi w górę drzewa aż do momentu obsłużenia.
Przykład obsługi błędu:

Code:
<Window x:Class="WpfExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfExample"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Validation.Error="TextBox_Error_1">
            <TextBox.Text>
                <Binding Path="Value" NotifyOnValidationError="True">
                    <Binding.ValidationRules>
                        <local:IsIntValidationRule/>
                        <ExceptionValidationRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <Button Content="Button" HorizontalAlignment="Left" Margin="161,128,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>

Code:
        private void TextBox_Error_1(object sender, ValidationErrorEventArgs e)
        {
            switch (e.Action)
            {
                case ValidationErrorEventAction.Added:
                    MessageBox.Show(e.Error.ErrorContent.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    break;
                case ValidationErrorEventAction.Removed:
                    System.Diagnostics.Trace.WriteLine("Błąd walidacji został usunięty");
                    break;
            }
        }


Brak komentarzy:

Prześlij komentarz