Lekce 7 - Upomínač narozenin ve VB.NET WPF - Logická vrstva
V minulém dílu, Upomínač narozenin v VB .NET WPF - Návrh oken, jsme navrhli kompletně formuláře pro naši aplikaci.
V tomto dílu se budeme zabývat návrhem logické vrstvy, tedy tříd, které obsahují logiku aplikace.
Osoba
V naší aplikaci budou zcela jistě figurovat osoby, vytvořme jim tedy třídu.
Vlastnosti
Osoba bude mít 4 vlastnosti: jméno, narozeniny, věk a zbývající počet dní do nejbližších narozenin. Jméno bude string, Narozeniny budou typu DateTime, Vek integer a ZbyvaDni také integer. První dvě vlastnosti jsou jednoduché:
Public Property Jmeno As String Public Property Narozeniny As DateTime
Tyto vlastnosti nastavíme pomocí parametrického konstruktoru. Třída vypadá zatím takto:
Public Class Osoba Public Property Jmeno As String Public Property Narozeniny As DateTime Public Sub New(jmeno As String, narozeniny As DateTime) Me.Jmeno = jmeno Me.Narozeniny = narozeniny End Sub End Class
Další dvě vlastnosti nebudou pouhou proměnnou, ale budou obsahovat další logiku. Takové vlastnosti je potom možné pomocí bindingu jednoduše zobrazovat na formuláři.
Věk
Vlastnost vypočítá a vrátí aktuální věk osoby v celých letech. Výpočet bohužel není jen o tom odečíst dva datumy, jelikož TimeSpan neumí zjistit počet let, pouze počet dní. Výpočet věku tedy provedeme následujícím způsobem:
- Získáme si aktuální datum (bez času) pomocí DateTime.Today.
- Věk spočítáme jako rozdíl roků v aktuálním datu a datu narozenin. Asi je vám jasné, že tento věk není přesný. Pokud jsme se narodili 1.2.1990 a je 1.1.2010, není nám 20 let, ale jen 19. Z toho důvodu provedeme korekci.
- V případě, že je aktuální datum menší (dříve) než datum narození po přidání námi vypočítaných let, nastal výše uvedený případ a my věk o rok snížíme.
- Hotový věk vrátíme.
Kód vlastnosti bude následující.
Public Property Vek As Integer Get Dim aktualniDatum As DateTime = DateTime.Today Dim stari As Integer = aktualniDatum.Year - Narozeniny.Year If aktualniDatum < Narozeniny.AddYears(Vek) Then stari -= 1 End If Return stari End Get Set(value As Integer) End Set End Property
ZbyvaDni
Vlastnost nám vrátí kolik dní zbývá do narozenin osoby. To zjistíme následujícím způsobem:
- Získáme si aktuální datum (bez času).
- Získáme datum dalších narozenin přičtením věku + 1 k datu narození.
- Data odečteme a celkový rozdíl ve dnech vrátíme. Jelikož je rozdíl typu double, musíme ho zkonvertovat na int.
Public Property ZbyvaDni As Integer Get Dim dnes As DateTime = DateTime.Today Dim dalsinarozeniny As DateTime = Narozeniny.AddYears(Vek + 1) Dim rozdil As TimeSpan = dalsinarozeniny - dnes Return rozdil.TotalDays End Get Set(value As Integer) End Set End Property
ToString
Jelikož budeme osoby vypisovat, přepíšeme třídě ještě metodu ToString() tak, aby vracela jméno osoby:
Public Overrides Function ToString() As String Return Jmeno End Function
Správce osob
Další logickou komponentou aplikace bude správce osob. Třída se bude starat o osoby, bude je umět přidávat, odebírat a jejich seznam ukládat do souboru a opětovně načíst. Konečně bude umět mezi osobami vyhledat tu, která má nejbližší narozeniny.
Přidejte si k projektu tedy třídu SpravceOsob.
Vlastnosti a atributy
Správce osob disponuje třemi veřejnými vlastnostmi. První je seznam osob typu ObservableCollection. S touto kolekcí jsme se v seriálu ještě nesetkali. Jedná se o chytřejší List, který na sobě umí vyvolat událost změny v případě, že se změní jeho obsah. Díky tomuto mechanismu se automaticky obnoví všechny kontrolky na formuláři, které mají nastavený jako zdroj dat právě tuto ObservableCollection. Asi si dokážete představit, že obnovovat ručně desítky kontrolek na formuláři v případě změny může být velice nepřehledné. Jakmile v naší aplikaci přidáme novou osobu, bude ihned vidět v seznamu osob aniž bychom ho obnovovali, obnoví se sám. ObservableCollection() inicializujeme v konstruktoru.
Pokud bychom chtěli implementovat i editaci osob, musela by třída Osoba implementovat rozhraní INotifyPropertyChanged. Jakákoli změna (např. jména) by se poté automaticky projevila ve všech kontrolkách všech formulářů, kde osoba figuruje. Tímto se však pro zjednodušení zabývat nebudeme.
Třída zatím vypadá takto:
Public Class SpravceOsob Public Property Osoby As ObservableCollection(Of Osoba) Public Sub New() Osoby = New ObservableCollection(Of Osoba)() End Sub End Class
Dalšími vlastnostmi jsou DnesniDatum, která vrátí dnešní datum. Dále NejblizsiOsoba, která vrátí osobu s nejbližšími narozeninami. Jejich kód:
Public Property NejblizsiOsoba As Osoba Public Property DnesniDatum As DateTime Get Return DateTime.Now End Get Set(value As DateTime) End Set End Property
Metody
Kromě přidávání a odebírání bude třída umět i nalézt osobu s nejbližšími narozeninami. Ukládání a načítání osob do/ze souboru necháme na později.
NajdiNejblizsi
Metoda najde a uloží osobu, která má nejbližší narozeniny. K vyhledání osoby v seznamu použijeme LINQ metodu OrderBy(), která osoby uspořádá podle toho, kolik dní zbývá do jejich narozenin. Výsledek uložíme do kolekce, jejíž typ neuvedeme, jak je u LINQu zvykem. Následně vrátíme první osobu. Metodu bychom měli volat jen tehdy, když jsou v seznamu nějaké osoby. Bude také privátní, jelikož ji budeme volat jen uvnitř třídy. Ačkoli by z kódu mělo být jasné, co metoda dělá, můžete se samozřejmě podívat na tutoriály v sekci (dostupné pouze pro C#) Kolekce a LINQ v C# .NET, kde je technologie LINQ detailně popsána.
Private Sub Najdinejblizsi() Dim serazeneOsoby = From o In Osoby Order By o.ZbyvaDni If serazeneOsoby.Count() > 0 Then NejblizsiOsoba = serazeneOsoby.First() Else NejblizsiOsoba = Nothing End If End Sub
Pridej
Metoda přidá novou osobu do ObservableCollection. Jelikož osobu přidáváme formulářem, hodí se nám, aby metoda brala v parametrech vlastnosti osoby a na jejich základě vytvořila novou instanci. Z data narození uložíme pouze část s datem, tedy bez času.
Před přidáním zkontrolujeme, zda jméno není příliš krátké nebo není zadané datum v budoucnosti. Pokud nějaká z těchto situací nastane, vyhodíme výjimku. Právě výjimky jsou správným způsobem, jak s chybami v objektových aplikacích pracovat.
Výjimky jsou detailněji popsané v sekci Práce se soubory v VB .NET. Pokud jste se s nimi ještě nesetkali, bude vám stačit vědět, že výjimka se vyvolá pomocí klíčového slova Throw, za kterým následuje instance výjimky. Výjimek máme několik typů včetně možnosti vytvořit si vlastní. V našem případě se nám hodí ArgumentException (chyba v argumentu). Do konstruktoru výjimky zadáváme text chyby. Jakmile je výjimka vyvolána, metoda již dále nepokračuje. Jak na chybu reagovat si ukážeme až budeme metodu volat z formuláře.
Při zadávání data kontrolkou DatePicker dostaneme datum jako typ DateTime. Pokud je v datu Nothing, nebylo zadané a vyhodíme též výjimku.
Public Sub Pridej(jmeno As String, datumNarozeni As DateTime) If jmeno.Length < 3 Then Throw New ArgumentException("Jméno je příliš krátké") End If If datumNarozeni = Nothing Then Throw New ArgumentException("Nebylo zadané datum narození") End If If datumNarozeni > DateTime.Today Then Throw New ArgumentException("Datum narození nesmí být v budoucnosti") End If Dim osoba As New Osoba(jmeno, datumNarozeni) Osoby.Add(osoba) Najdinejblizsi() End Sub
Na konci metody vyhledáme nejbližší osobu, protože to může být zrovna ta přidaná.
Odeber
Metoda odebere osobu z ObservableCollection. Protože vždy budeme chtít odebírat již hotovou osobu, bere metoda v parametru právě tu. Po odebrání opět obnovíme nejbližší osobu.
Public Sub Odeber(osoba As Osoba) Osoby.Remove(osoba) Najdinejblizsi() End Sub
Pokračovat budeme příště, Upomínač narozenin v VB .NET WPF - Propojení vrstev, kdy aplikaci zprovozníme. Dosavadní zdrojový kód je ke stažení níže.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 86x (333.75 kB)
Aplikace je včetně zdrojových kódů v jazyce VB