Poprawnie zaprojektowana aplikacja powinna weryfikować dane w każdej warstwie systemu. Oczywiście najważniejszym miejscem jest warstwa biznesowa ale dobrym zwyczajem jest walidacja również w warstwie prezentacji. W idealnym interfejsie użytkownik nie jest w stanie wprowadzić błędnych danych. Podstawowym przykładem są pola edycyjne w których powinno się wpisać np. ilość sprzedanego produktu. Użytkownik nie powinien mieć możliwości wprowadzenia tekstu w takie pole.
Zacznijmy od prostej sprawy – akceptacja tylko cyfr.
public class IntNumberTextBox:System.Windows.Controls.TextBox { protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e) { e.Handled = !ValidateText(e.Text); base.OnPreviewTextInput(e); } private bool ValidateText(string text) { foreach (Char character in text) { if (System.Char.IsDigit(character) == false) return false; } return true; } }
Jak widać wystarczy tylko przeładować metodę OnPreviewTextInput i ustawić flagę Handled na true w przypadku gdy wprowadzony znak jest niedozwolony.
W przypadku liczb rzeczywistych musimy umożliwić dodatkowo wprowadzanie przecinków lub kropek. Znak oddzielający część dziesiętną od całkowitej zależy od ustawień regionalnych w systemie operacyjnym. W C# możemy sprawdzić jaki to jest znak za pomocą właściwości System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator.
public class RealNumberTextBox:System.Windows.Controls.TextBox { protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e) { e.Handled = !ValidateText(e.Text); base.OnPreviewTextInput(e); } private bool ValidateText(string text) { if ( text == System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator) return true; foreach (Char character in text) { if (System.Char.IsDigit(character) == false) return false; } return true; } }
Inne ciekawe wartości, zależne od ustawień regionalnych, które są przydatne w walidacji to m.in CurrencyDecimalSeparator, CurrencyGroupSeparator, CurrencySymbol, NegativeSign, NegativeInfinitySymbol.
Teraz pozostało nam tylko wykorzystać nowo utworzoną kontrolkę w pliku XAML. Najpierw należy zadeklarować przestrzeń nazw:
<Window x:Class="Sample.Views.Product.Product" xmlns:controls="clr-namespace:Sampple.Controls" inne deklaracje >
Następnie korzystamy z kontrolki w sposób analogiczny do standardowych kontrolek:
<controls:IntNumberTextBox HorizontalAlignment="Left" Width="200" Text="tekst" />
Pamiętajmy, że walidacja w dolnych warstwach jest zwykle wolniejsza ponieważ należy połączyć się najpierw np. z bazą danych lub z usługą sieciową. Ponadto korzystanie z aplikacji z walidacją w warstwie prezentacji jest po prostu łatwiejsze dla użytkownika.