Walidacja danych z użyciem IDataErrorInfo

Witam

Ten wpis jest kontynuacją poprzedniego wpisu w którym poruszyłem kwestie użycia Dispatchera.

W dzisiejszym wpisie o walidacji wprowadzanych danych przez użytkownika z wykorzystaniem interfejsu IDataErrorInfo. Aby go użyć trzeba zaimplementować jego dwóch członków. Właściwość Error która służy do podawania informacji o błędzie w walidacji (co jest błędne w danym obiekcie). Ta właściwość nie jest wykorzystywana w WPF. Druga właściwością jest Item który pobiera wiadomość błędu dla danej nas interesującej właściwości, która chcemy walidować.

Korzystając z programiku do skanownia portów z poprzedniego wpisu dodajemy do ViewModelu poniższy kod który wykorzystuje IDataErrorInfo Oczywiście nie zapomnij o zaimplementowaniu interfejsu do viewmodelu lub modelu :).


// Property nie używane w WPF, lecz należy to dodać aby zaimplementować interfejs.
public string Error
        {
            get { return String.Empty; }
        }
// Property Item tu obsługujemy walidacje
        public string this[string propertyName]
        {
            get
            {
                {
                    String errorMessage = String.Empty;
                    switch (propertyName)
                    {
                        case "Host":
                            if (String.IsNullOrEmpty(Host))
                            {
                                errorMessage = "IP addres is required";
                                _valid = false;
                            }
                            //Regex IP adresu
                            else if (Regex.IsMatch(Host, @"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$") == false)
                            {
                                errorMessage = "This is not valid IP number";
                                _valid = false;
                            }

                            break;
                    }
                    return errorMessage;
                }
            }
        }

Aby zobaczyć efekt błędnej walidacji musimy w widoku (xaml-u) stworzyć odpowiedni styl oraz do danej kontrolki włączyć powiadamianie o błędach poprzez dodanie do niej ValidatesOnDataErrors=True.

Kontrolka z walidacja na błędy:

<TextBox Text="{Binding Host,
                        UpdateSourceTrigger=PropertyChanged,
                        ValidatesOnDataErrors=True}"
                        MaxWidth="300" MinWidth="300"
                        Padding="1" FontSize="20"/>

Styl do obsługi walidacji, ten akruat dotyczy tylko textboxów:


<Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip" Value="{Binding RelativeSource
                        ={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}" />
                </Trigger>
            </Style.Triggers>
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <DockPanel DockPanel.Dock="Right">
                            <AdornedElementPlaceholder>
                                <Border BorderBrush="Red" BorderThickness="2"/>
                            </AdornedElementPlaceholder>
                            <TextBlock Text="*" Foreground="Red"
                                       ToolTip="{Binding Path=AdornedElement.ToolTip,
                                       RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Adorner}}}"/>
                        </DockPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Jeżeli chcielibyśmy de-aktywować któryś z przycisków obsługujących komendę od której zależałoby na poprawności danych to najprościej dodać zmienną typu bool i zmieniać jej wartość podczas błędów walidacji na false (patrz wyżej w metodzie Item interfejsu zaznaczona linia 19 z zmienną valid, zmieniana na false w trakcie błędnej walidacji)

W przypadku gdy korzystamy z komend RelayCommand jak w załączonym programie aby dezaktywować button wystarczy zwracać w funkcji CanExecuteCommand wartość wyżej opisanej zmienej.

private bool CanScanExecute()
        {
            return _valid;
        }

Powrót do stanu true uzyskamy poprzez przestawienie wartości w wnętrzu właściwości która walidujemy.

public string Host
        {
            get
            {
                return _host;
            }
            set
            {
                if (_host == value)
                    return;
                _host = value;
                _valid = true; //update po zmianie zawartości
                RaisePropertyChanged("Host");
            }
        }

To z grubsza wszystko co dotyczy prostej walidacji danych przy pomocy tego interfejsu.
Źródła programu SkanerMVVM z walidacją.