7. diel - PRIPOMIENKOVÉ narodenín v C # .NET WPF - Logická vrstva
V minulej lekcii, PRIPOMIENKOVÉ narodenín v C # .NET WPF - Návrh okien , sme navrhli kompletne formuláre pre našu aplikáciu. V tomto C# .NET tutoriálu sa budeme zaoberať návrhom logické vrstvy, teda tried, ktoré obsahujú logiku aplikácie.
Osoba
V našej aplikácii budú celkom iste figurovať osoby, vytvorme im teda
triedu. Pred triedu nezabudnite dať modifikátor public
.
Vlastnosti
Osoba bude mať 4 vlastnosti:
Jmeno
- meno typustring
Narozeniny
- narodeniny typuDateTime
Vek
- vek typuint
ZbyvaDni
- zostávajúci počet dní do najbližších narodenín typuint
Prvé dve vlastnosti sú jednoduché:
public string Jmeno { get; set; } public DateTime Narozeniny { get; set; }
Tieto vlastnosti nastavíme pomocou parametrického konstruktoru. Trieda vyzerá zatiaľ takto:
public class Osoba { public string Jmeno { get; set; } public DateTime Narozeniny { get; set; } public Osoba(string jmeno, DateTime narozeniny) { Jmeno = jmeno; Narozeniny = narozeniny; } }
Ďalšie dve vlastnosti nebudú obyčajnou premennú, ale budú obsahovať ďalšie logiku. Takéto vlastnosti je potom možné pomocou binding jednoducho zobrazovať na formulári.
Vek
Vlastnosť vypočíta a vráti aktuálne vek osoby v celých rokoch.
Výpočet bohužiaľ nie je len o tom odpočítať dva dátumy, pretože
TimeSpan
nevie zistiť počet rokov, iba počet dní. Výpočet
veku teda vykonáme nasledujúcim spôsobom:
- Získame si aktuálny dátum (bez času) pomocou
DateTime.Today
. - Vek spočítame ako rozdiel rokov v aktuálnom dátume a dátume narodenín. Asi je vám jasné, že tento vek nie je presný. Ak sme sa narodili 1.2.1990 a je 1.1.2010, nie je nám 20 rokov, ale len 19. Z toho dôvodu vykonáme korekciu.
- V prípade, že je aktuálny dátum menšia (skôr) ako dátum narodenia po pridaní nami vypočítaných rokov, nastal vyššie uvedený prípad a my vek o rok znížime.
- Hotový vek vrátime.
Kód vlastnosti bude nasledujúci:
public int Vek { get { DateTime dnes = DateTime.Today; int vek = dnes.Year - Narozeniny.Year; if (dnes < Narozeniny.AddYears(vek)) vek--; return vek; } }
ZbyvaDni
Vlastnosť nám vráti koľko dní zostáva do narodenín osoby. To zistíme nasledujúcim spôsobom:
- Získame si aktuálny dátum (bez času).
- Získame dátum ďalších narodenín pripočítaním veku + 1 k dátumu narodenia.
- Dáta odčítame a celkový rozdiel v dňoch vrátime. Keďže je rozdiel
typu
double
, musíme ho skonvertovať naint
.
public int ZbyvaDni { get { DateTime dnes = DateTime.Today; DateTime dalsiNarozeniny = Narozeniny.AddYears(Vek + 1); TimeSpan rozdil = dalsiNarozeniny - DateTime.Today; return Convert.ToInt32(rozdil.TotalDays); } }
ToString ()
Keďže budeme osoby vypisovať, prepíšeme triede ešte metódu
ToString()
tak, aby vracala meno osoby:
public override string ToString() { return Jmeno; }
Správca osôb
Ďalšie logickú komponentom aplikácia bude správca osôb. Trieda sa bude starať o osoby, bude ich vedieť pridávať, odoberať a ich zoznam ukladať do súboru a opätovne načítať. Konečne bude vedieť medzi osobami vyhľadať tú, ktorá má najbližšie narodeniny.
Pridajte si k projektu teda triedu SpravceOsob
a urobte ju
verejnú.
Vlastnosti a atribúty
Správca osôb bude disponovať tromi verejnými vlastnosťami.
Prvý je zoznam osôb typu ObservableCollection
. S touto
kolekciou sme sa v kurze ešte nestretli. Jedná sa o múdrejší
List
, ktorý na sebe vie vyvolať udalosť zmeny v prípade, že sa
zmení jeho obsah. Vďaka tomuto mechanizmu sa automaticky obnoví všetky prvky
na formulári, ktoré majú nastavený ako zdroj údajov práve túto
ObservableCollection
. Asi si dokážete predstaviť, že obnovovať
ručne desiatky formulárových prvkov v prípade zmeny môže byť veľmi
neprehľadné. Akonáhle v našej aplikácii pridáme novú osobu, bude ihneď
vidieť v zozname osôb bez toho aby sme ho obnovovali, obnoví sa sám.
ObservableCollection()
inicializujeme v konstruktoru.
Ak by sme chceli implementovať aj editáciu osôb, musela by trieda
Osoba
implementovať rozhranie INotifyPropertyChanged
.
Akákoľvek zmena (napr. Mená) by sa potom automaticky prejavila vo všetkých
prvkoch všetkých formulárov, kde osoba figuruje. Týmto sa však pre
zjednodušenie zaoberať nebudeme.
Trieda zatiaľ vyzerá takto:
public class SpravceOsob { public ObservableCollection<Osoba> Osoby { get; set; } public SpravceOsob() { Osoby = new ObservableCollection<Osoba>(); } }
Ďalšími vlastnosťami sú:
DnesniDatum
, ktorá vráti dnešný dátum.- A
NejblizsiOsoba
, ktorá vráti osobu s najbližšími narodeninami.
Ich kód:
public Osoba NejblizsiOsoba { get; set; } public DateTime DnesniDatum { get { return DateTime.Now; } }
Metódy
Okrem pridávanie a odoberanie bude trieda vedieť aj nájsť osobu s najbližšími narodeninami. Ukladanie a načítanie osôb do / zo súboru necháme na neskôr.
NajdiNejblizsi ()
Metóda nájde a uloží osobu, ktorá má najbližšie narodeniny. Na
vyhľadanie osoby v zozname použijeme LINQ
metódu OrderBy()
, ktorá osoby usporiada podľa toho, koľko dní
zostáva do ich narodenín. Výsledok uložíme do kolekcie, ktorej typ
neuvedieme a použijeme namiesto toho kľúčové slovo var
, ako je
v LINQ zvykom. Následne vrátime prvú osobu. Metódu by sme mali volať len
vtedy, keď sú v zozname nejakej osoby. Bude tiež privátne, pretože ju
budeme volať len vnútri triedy. Hoci by z kódu malo byť jasné, čo metóda
robí, môžete sa samozrejme pozrieť na tutoriály v sekcii Kolekcia a LINQ v C# .NET, kde je technológia
LINQ detailne popísaná.
private void NajdiNejblizsi() { var serazeneOsoby = Osoby.OrderBy(o => o.ZbyvaDni); if (serazeneOsoby.Count() > 0) NejblizsiOsoba = serazeneOsoby.First(); else NejblizsiOsoba = null; }
Pridajme ()
Metóda pridá novú osobu do ObservableCollection
. Keďže
osobu budeme pridávať formulárom, hodí sa nám, aby metóda brala v
parametroch vlastnosti osoby a na ich základe vytvorila novú inštanciu. Z
dátumu narodenia uložíme iba časť s dátumom, teda bez času.
Pred pridaním skontrolujeme, či meno nie je príliš krátke alebo nie je zadaný dátum v budúcnosti. Ak nejaká z týchto situácií nastane, vyvoláme výnimku. Práve výnimky sú jediným správnym spôsobom, ako s chybami v objektových aplikáciách pracovať.
Výnimky sú detailnejšie popísané v sekcii Práca so súbormi v C# .NET. Ak ste sa s nimi ešte
nestretli, bude vám stačiť vedieť, že výnimka sa vyvolá pomocou
kľúčového slova throw
, za ktorým nasleduje inštancie
výnimky. Výnimiek máme niekoľko typov vrátane možnosti vytvoriť si
vlastný. V našom prípade sa nám hodí ArgumentException
(chyba
v argumentu). Do konstruktoru výnimky zadávame text chyby. Akonáhle je
výnimka vyvolaná, metóda už ďalej nepokračuje. Ako na chybu reagovať si
ukážeme až budeme metódu volať z formulára.
Pri zadávaní dáta ovládacím prvkom DatePicker
dostaneme
dátum ako typ DateTime?
. Ak ste dočítali objektový kurz C# až do konca, viete, že otáznik
značí tzv. Nullovatelný typ. To je akési rozšírenie hodnotového
dátového typu o hodnotu null
, ktorú hodnotový typ bežne
obsahovať nemôže. Pokiaľ je v dátume null
, znamená to, že
nebolo zadané a vyhodíme tiež výnimku. K hodnote nullovatelného typu
pristupuje cez vlastnosť Value
.
public void Pridej(string jmeno, DateTime? datumNarozeni) { if (jmeno.Length < 3) throw new ArgumentException("Jméno je příliš krátké"); if (datumNarozeni == null) throw new ArgumentException("Nebylo zadané datum narození"); if (datumNarozeni.Value.Date > DateTime.Today) throw new ArgumentException("Datum narození nesmí být v budoucnosti"); Osoba osoba = new Osoba(jmeno, datumNarozeni.Value.Date); Osoby.Add(osoba); NajdiNejblizsi(); }
Na konci metódy obnovíme najbližší osobu, pretože to môže byť práve tá pridaná.
Odober ()
Metóda odoberie osobu z ObservableCollection
. Pretože vždy
budeme chcieť odoberať už hotovú osobu, berie metóda v parametri práve
tú. Po odobratí opäť obnovíme najbližšej osobu.
public void Odeber(Osoba osoba) { Osoby.Remove(osoba); NajdiNejblizsi(); }
Pokračovať budeme v lekcii, PRIPOMIENKOVÉ narodenín v C # .NET WPF - Prepojenie vrstiev , kedy aplikáciu sprevádzkujeme. Doterajšie zdrojový kód je k stiahnutiu nižšie.