Silverlight 4–použití DataAnnotations
Úvod
Namespace System.ComponentModel.DataAnnotations nabízí celou řadu atributů, které můžeme v naší aplikaci využít. V následující ukázce si ukážeme použití několika atributů v různých případech.
V ukázkové aplikaci budeme pracovat se třídou Person
public class Person { public string FirstName { get; set; } public string LastName { get; set; } public SexType SexType { get; set; } public string Pin { get; set; } } public enum SexType { Male, Female }
No a když si vytvoříme kolekci těchto osob
public class People : ObservableCollection<Person> { public People() { this.Add(new Person() { FirstName = "Lukas", LastName = "Kubis", SexType = SexType.Male, Pin = "123456"}); this.Add(new Person() { FirstName = "Jan", LastName = "Novak", SexType = SexType.Male, Pin = "123456" }); this.Add(new Person() { FirstName = "Andrejka", LastName = "Bogey", SexType = SexType.Female, Pin = "123456" }); } }
a zobrazíme v Gridu (AutoGenerateColumns = True), dostaneme následující výsledek
Data se zobrazují správně, ale co když budume chtít mít názvy sloupců česky a poslední sloupec Pin skrýt ?
Samozřejmě můžeme nastavit AutoGenerateColumns na False a definovat sloupečky tak jak chci s příslušným Header textem, nebo přepsat událost, ve které se vytvářejí sloupečky a zde nastavit Header text a skrýt nepotřebný sloupec Pin.
Obě varianty budou fungovat, ale my si ukážeme aspoň podle mě lepší způsob jak toho docílit.
DisplayAttribute
Pro změnu zobrazení názvu sloupce využijeme DisplayAttribute, kde do vlastnosti Name napíšeme náš vlastní text. Každou vlastnost třídy Person, u které budeme chtít změnit zobrazovaný text označíme tímto atributem. Pro skrytí sloupce slouží vlastnost AutoGenerateField, kterou nastavíme na false
public class Person { [DisplayAttribute(Name = "Jméno")] public string FirstName { get; set; } [DisplayAttribute(Name = "Příjmení")] public string LastName { get; set; } [DisplayAttribute(Name = "Pohlaví")] public SexType SexType { get; set; } [DisplayAttribute(AutoGenerateField = false)] public string Pin { get; set; } }
Po těchto jednoduchých úpravách dostaneme hned lepší výsledek
V případě, že vyvíjíme lokalizované aplikace, nemusíme řetězec zapisovat přímo do vlastnosti Name, ale můžeme využít ResourceType a odkázat na příslušné Resources, ve kterých budou řetězce přeloženy do jednotlivých jazyků.
Dále se zde zmíním o vlastnosti Order, která určuje v jakém pořadí se sloupce vygenerují. Nastavíme-li jménu Order = 2 a příjmení Order = 1, budeme mít v Gridu zobrazeno nejdříve Příjmení a až potom Jméno. Poslední vlastnost Description, kterou chci představit si necháme na později.
Validace
Další ukázka použití atributů se bude zabývat validací. Vytvoříme si formulář, kde bude uživatel vyplňovat informace o osobě a při špatném zadání se mu zobrazí informace o chybě.
Opět provedeme úpravu třídy Person, kde nyní nebudeme využívat automatické vlastnosti
public class Person { private string _firstName; private string _lastName; private SexType _sexType; [Display(Name = "Jméno", Order = 1)] public string FirstName { get { return this._firstName; } set { this._firstName = value; } } [Display(Name = "Příjmení", Order = 2)] public string LastName { get { return this._lastName; } set { this._lastName = value; } } [Display(Name = "Pohlaví")] public SexType SexType { get { return this._sexType; } set { this._sexType = value; } } [Display(AutoGenerateField = false)] public string Pin { get; set; } }
A náš jednoduchý formulář vypadá následovně (obsah XAMLu vysvětlím později)
<Grid x:Name="LayoutRoot" Margin="2"> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="300"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <!-- FirstName --> <sdk:Label Content="Jméno" IsRequired="True" Margin="5" /> <StackPanel Orientation="Horizontal" Grid.Column="1"> <TextBox x:Name="ui_txtFirstName" Width="200" Text="{Binding FirstName, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/> <sdk:DescriptionViewer Target="{Binding ElementName=ui_txtFirstName}" /> </StackPanel> <!-- FirstName --> <sdk:Label Grid.Row="1" Content="Příjmení" IsRequired="True" Margin="5" /> <StackPanel Grid.Row="1" Orientation="Horizontal" Grid.Column="1"> <TextBox x:Name="ui_txtLastName" Width="200" Text="{Binding LastName, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/> <sdk:DescriptionViewer Target="{Binding ElementName=ui_txtLastName}" /> </StackPanel> <!-- SexType --> <sdk:Label Grid.Row="2" Content="Pohlaví" IsRequired="True" Margin="5" /> <StackPanel Grid.Row="2" Orientation="Horizontal" Grid.Column="1"> <TextBox x:Name="ui_txtSexType" Width="200" Text="{Binding SexType, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/> <sdk:DescriptionViewer Target="{Binding ElementName=ui_txtSexType}" /> </StackPanel> <!-- ValidationSummary--> <sdk:ValidationSummary Grid.Row="3" Grid.ColumnSpan="2"/> </Grid>
Podíváme se tedy na několik atributů, které nám mohou být nápomocné při provádění validace.
- RangeAttribute – kontroluje zda je zadaná hodnota v povoleném rozsahu
- RegularExpressionAttribute – validace pomocí regulárního výrazu
- RequiredAttribute – označuje povinnou položku
- StringLengthAttribute – specifikuje minimální a maximální délku řetězce
- EnumDataType – umožňuje namapovat Enum na sloupec
Poznámka: Každý validační atribut má vlastnost ErrorMessage, ve které uvedeme chybovou hlášku a nebo můžeme opět využít Resources.
Opět se pustíme do úpravy třídy Person a přidáme atributy pro validaci
[Required(ErrorMessage = "Jméno je povinné")] [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$", ErrorMessage = "Čísla a speciální znaky nejsou ve jméně povoleny.")] public string FirstName [Required(ErrorMessage = "Příjmení je povinné")] [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$", ErrorMessage = "Čísla a speciální znaky nejsou v příjmení povoleny.")] public string LastName [EnumDataType(typeof(SexType))] public SexType SexType
Když ovšem spustíme aplikaci a v editačním formuláři nevyplníme třeba jméno tak se nic nestane. Je potřeba provést ještě několik kroků. Prvním důležitým krokem je upravit jednotlivé settery našich vlastností. Zde použijeme třídu Validator a pouze zavoláme metodu ValidateProperty, která provede validaci vůči našim atributům.
public string FirstName { get { return this._firstName; } set { Validator.ValidateProperty(value, new ValidationContext( this, null, null) { MemberName = "FirstName" }); this._firstName = value; } }
Validaci vlastnosti provádíme ještě před přiřazením, protože když validace selže, dojde k vyvolání výjimky a je třeba nastavit v XAMLu ValidatesOnExceptions=True a NotifyOnValidationError=True
Nyní už po spuštění aplikace a zadání špatných údajů dostaneme informace o chybách.
Ještě než ukočíme povídání o DataAnnotations, tak bych se rád vrátil k XAMLu a některým pomocným ovládacím prvkům a vlastnosti Description Display atributu.
Na obrázku výše vidíte nejníže souhrn všech validačních chyb. O zobrazení se stará ValidationSummary, který pouze stačí přidat do UI a není potřeba nic nastavovat. Dále si můžete všimnout takového malého kolečka s “i”, zde se jedná o ovládací prvek DescriptionViewer. Pomocí vlastnosti Target svážeme ovládací prvek s textboxem (např. pro zadání příjmení) a jelikož je textbox napojen na vlastnost LastName, která má nastaven Description tak po najetí myši přes tuto ikonku dojde k zobrazení příslušného textu.
Materiály ke stažení
Ukázkový projekt stáhnete zde Pro jakýkoliv dotaz mně neváhejte kontaktovat buď pomocí komentářů pod článkem nebo zde
No škoda, že se to nedá použít s autoproperty, definovat property takto je dost opruz a navíc je to pořád ten stejný kod.
Definovíní IPropertyChanged pomocí AOP code.google.com/.../notifypropertyw