Projektowanie, Programowanie, Codzienność – BeniaminZaborski.com

30 Listopad 2009

Error Provider

Filed under: How Can I Take ... — Tags: , , , — Beniamin Zaborski @ 19:51

W poniższym artykule chciałbym poruszyć kwestię związana z walidacją obiektów. Oczywiste jest, że walidacja jest niezbędnym elementem każdej dobrze zaprojektowanej aplikacji biznesowej. Jednak nie sam sposób walidowania obiektów jest przewodnim tematem tego artykułu. Chciałbym przedstawić pewien dość oczywisty sposób informowania użytkownika o błędach. Do napisania tego artykułu zainspirowało mnie pytanie mojego znajomego … właśnie na podobny temat. Okazuje się, że nie wszystko jest tak oczywiste jak sądzimy. Na wstępie chciałbym zaznaczyć, iż artykuł dotyczy aplikacji Window Forms.
Większość z nas pewnie widziała w aplikacjach ASP.NET ikonki przy polach edycyjnych informujące o wymagalności danego pola lub zbyt dużej ilość znaków – ogólnie o niespełnionych regułach walidacyjnych. Podobny efekt możemy uzyskać w aplikacjach Window Forms. Tu kolejna dobra wiadomość – za pomocą standardowych kontrolek i to w łatwy sposób. Odpowiedzialna za to jest kontrolka o nazwie ErrorProvider. Poniższy zrzut ekranu przedstawia wspomnianą kontrolkę w akcji.

Niespełniona reguła walidacyjna na wskazanym property obiektu powoduje wyświetlenie ikony przy odpowiedniej kontrolce. Szczegóły niespełnionych reguł są wyświetlane w tooltipie. Wiemy zatem co chcemy uzyskać, teraz pytanie jak?

Zacznę może od samego obiektu który podlega walidacji. W aplikacjach biznesowych jest to z reguły jakiś DataTransferObject. Kontrolka ErrorProvider potrzebuje, aby dostarczyć do niej informacji o niespełnionych regułach walidacyjnych. Ta informacja to zwykły string czyli komunikat który ma się wyświetlić użytkownikowi. Odpowiedzialny za to jest interfejs IDataErrorInfo.

Interfejs jest dość prosty bo posiada tylko dwie właściwości:

  • string Error { get; }
  • string Item[string columnName] { get; }

Jak się okazuje dalej implementacja tego interfejsu w naszej klasie DataTransferObject również nie jest trudna. Zakładam, że nasz DataTransferObject posiada już sam mechanizm walidowania np. wykorzystujący całkiem poręczny Application Validation Block pochodzący z Enterprise Library. Nie pozostaje teraz nic innego jak zaimplementować IDataErrorInfo w naszej klasie DataTransferObject.

public abstract class DataTransferObject : IDataTransferObject, IValidatable, IDataErrorInfo
{
// pominięta część kodu klasy nieistotna w omawianym kontekście
string IDataErrorInfo.Error
{
get
{
if (!IsValid)
return BrokenValidationRules.GetDescriptionBrokenRules();
else
return String.Empty;
}
}

string IDataErrorInfo.this[string columnName]
{
get
{
string result = string.Empty;
if (!IsValid)
{
IBrokenValidationRule brokenRule = BrokenValidationRules.GetBrokenRule(columnName);
if (brokenRule != null)
result = brokenRule.Description;
}
return result;
}
}
}

Właściwość Error zwraca nam listę komunikatów o niespełnionych regułach na wskazanym obiekcie. Indekser zwraca nam natomiast listę komunikatów niespełnionych reguł dla wskazanej właściwości obiektu. Parametr columnName określa nazwę właściwości obiektu.

Przedstawiona klasa nie posiada pełnej implementacji, a jedynie te elementy które są istotne w omawianym kontekście. Oczywiste jest, że klasa musi mieć w tym wypadku kolekcję niespełnionych reguł walidacyjnych, która jest odpowiednio uzupełniana podczas wywołania walidacji. Na tej kolekcji zresztą bazują zaimplementowane właściwości z interfejsu IDataErrorInfo. W ten sposób chciałem pokazać, iż sam mechanizm walidacji jest zupełnie niezależny od implementacji IDataErrorInfo i po wprowadzeniu kilku własnych interfejsów może być łatwo wymieniany na inny.

Teraz możemy zająć się już interfejsem użytkownika. Pierwsze co należy zrobić to położyć na widoku kontrolkę ErrorProvider, np. przeciągając z toolboxa. Kolejnym krokiem jest zbindowanie naszego obiektu (dziedziczącego z DataTransferObject) z kontrolkami i przypisanie tego obiektu jako źródła danych do właściwości DataSource kontrolki ErrorProvider. Jeśli dodajemy kontrolkę ErrorProvider nie poprzez designera warto pamiętać o ustawieniu właściwości ContainerControl na odpowiednią formę/kontrolkę.

Sama kontrolka ErrorProvider posiada jeszcze kilka ciekawych właściwości jak: BlinkRate (częstotliwość pulsowania), BlinkStyle (kiedy ma pulsować ikonka) oraz Icon.

Powodzenia w implementacji wizualizacji wyników walidacji we własnej aplikacji w ten jakże prosty sposób.

3 komentarzy »

  1. nauczylem sie bardzo wiele

    Komentarz - autor: online — 21 Grudzień 2009 @ 04:04

  2. A może wiesz jak użyć tej kontrolki jeśli mamy w DTO właściwość np. typu Adres, która posiada jeszcze swoje pola?

    Komentarz - autor: arekor — 17 Sierpień 2010 @ 12:16

  3. Tu ErrorProvider ma pewien problem. Tak na prawdę nie udało mi się znaleźć w pełni satysfakcjonującego rozwiązania. Dostępne rozwiązania jakie znam to:
    – kolejny ErrorProvider dla zagnieżdżonego obiektu (ale co gdy mamy ich więcej?)
    – budowanie „płaskich” obiektów, tj. bez zagnieżdżeń (trochę głupie)
    – „opakowywanie” wywołań właściwości zagnieżdżonych obiektów we właściwości obiektu nadrzędnego (to rozwiązanie mogło by być). Można by się pokusić w tym wypadku o jakiś uniwersalny mechanizm z wykorzystaniem refleksji.

    Komentarz - autor: Beniamin Zaborski — 17 Sierpień 2010 @ 21:50


RSS feed for comments on this post. TrackBack URI

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

Stwórz darmową stronę albo bloga na WordPress.com.

%d bloggers like this: