Letní akce! Lákají tě IT školení C#, Javy a PHP v Brně? Přihlas se a napiš nám do zpráv kód "BRNO 500" pro slevu 500 Kč na libovolný brněnský kurz. Lze kombinovat se slevami uvedenými u školení i použít pro více kurzů. Akce končí 28.7.

Lekce 5 - Upomínač narozenin - Propojení prezentační a logické vrstvy

C# .NET Formuláře Windows Forms Upomínač narozenin - Propojení prezentační a logické vrstvy

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Upomínač narozenin - Logická vrstva, jsme naprogramovali většinu logické vrstvy aplikace pro upomínání narozenin. Dnes v C# .NET tutoriálu aplikaci zprovozníme.

Oddělení prezentace a logiky

Nyní máme dokončenou tzv. prezentační část aplikace (formuláře) a logickou část (třídy). Tyto 2 vrstvy se v aplikaci striktně oddělují, jelikož jinak je kód velmi nepřehledný. Nikdy byste neměli provádět výpočty, zápisy do souborů, databáze a podobné věci přímo v kódu formuláře! Vždy si vytvoříme třídu, která poskytuje příslušné metody a tuto třídu z formuláře pouze používáme. Logika zůstane ve třídě. Třída by naopak vůbec neměla vědět o formuláři. Neměla by tedy např. zobrazovat chybové hlášky, ale pouze vyvolávat v případě chyby výjimky. Je potom na formuláři, aby uživateli chybu zobrazil. Právě formulář je ta část aplikace, která s uživatelem komunikuje. Žádná jiná to nedělá.

Pokud vás napadlo, že naše jednoduchá kalkulačka, kterou jsme vytvořili v prvních lekcích kurzu, byla návrhově špatně, máte pravdu. Z důvodu jednoduchosti jsme napsali výpočty rovnou do obslužné metody tlačítka. Správně bychom měli mít nějakou třídu, která by výsledky počítala a tu bychom z formuláře pouze volali.

Dnes si tedy ukážeme, jak se to dělá správně.

Propojení prezentace a logiky

Přejdeme do zdrojového kódu formuláře PrehledForm a třídě přidáme privátní atribut typu SpravceOsob, ve kterém rovnou vytvoříme instanci správce:

private SpravceOsob spravceOsob = new SpravceOsob();

Instance správce se vytvoří při vytvoření formuláře a formulář s ní dále bude komunikovat a tak provádět úkony, které si přeje uživatel.

V konstruktoru formuláře nastavíme dnesLabel na aktuální datum a ListBoxu nastavíme vlastnost DataSource na BingList Osoby na správci osob. Tím napojíme ListBox na BindingList, odteď bude zobrazovat jeho obsah a pokud se do listu něco přidá, projeví se to i v ListBoxu.

public PrehledForm()
{
        InitializeComponent();

        dnesLabel.Text = DateTime.Now.ToLongDateString();
        osobyListBox.DataSource = spravceOsob.Osoby;
}
Přidávání a mazání osob

Abychom něco konečně také viděli, přejdeme k přidávání osob. Nejprve přejdeme do kódu formuláře OsobaForm, kde si stejně jako v předchozím formuláři připravíme správce osob jako privátní atribut. Kdybychom zde i vytvořili jeho instanci, nebylo by nám to moc platné, jelikož osoby by byly načtené ve správci v hlavním formuláři. A načítat je znovu by bylo neefektivní. Necháme si tedy hotového a načteného správce předat konstruktorem a uložíme ho do připravené proměnné:

private SpravceOsob spravceOsob;

public OsobaForm(SpravceOsob spravceOsob)
{
        InitializeComponent();
        this.spravceOsob = spravceOsob;
}

Nyní naklikneme tlačítko OK a do správce přidáme osobu pomocí hodnot, které uživatel do jednotlivých prvků zadal. K hodnotě v TextBoxu přistoupíme pomocí vlastnosti Text, k hodnotě v DateTimePickeru pomocí vlastnosti Value.

Určitě si vzpomínáte, že metoda Pridej() vyvolá výjimku v případě příliš krátkého jména nebo data v budoucnosti. Proto kód s přidáním vložíme do bloku try, za kterým bude následovat blok catch. Pokud výjimka v bloku try nastane, program se ihned přesune do bloku catch, kde pomocí MessageBoxu zobrazí chybovou hlášku. Pokud bychom výjimku takto neošetřili, způsobila by pád aplikace.

private void okButton_Click(object sender, EventArgs e)
{
        try
        {
                spravceOsob.Pridej(jmenoTextBox.Text, narozeninyDateTimePicker.Value);
                Close();
        }
        catch (Exception ex)
        {
                MessageBox.Show(ex.Message, "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }
}

Ke zprávě výjimky se dostaneme přes vlastnost Message. Všimněte si také, že zprávě nastavujeme ikonku vykřičníčku. V metodě již neřešíme žádnou logiku a je díky tomu poměrně krátká.

V tomto formuláři jsme skončili. Přesuneme se zpět do PrehledForm, tentokrát do grafické části a naklikneme tlačítka pridatButton a odebratButton.

private void pridatButton_Click(object sender, EventArgs e)
{
        OsobaForm osobaForm = new OsobaForm(spravceOsob);
        osobaForm.ShowDialog();
}

V obslužné metodě tlačítka pridejButton vytvoříme novou instanci formuláře OsobaForm, které předáme místního správce osob. Na instanci následně zavoláme metodu ShowDialog(). Ta zobrazí nový formulář (stejně jako metoda Show()) a k tomu ještě zablokuje zbytek aplikace, který se zaktivní až v případě, kdy se dialog zavře. Výsledkem je, že se s hlavním formulářem nedá pracovat dokud dialog nepotvrdíme či neukončíme. U dialogu (rozumějte pomocného formuláře, který slouží nejčastěji k zadání dat) se toto většinou dělá. I když nám by v podstatě nevadilo, kdyby uživatel během zadávání nové osoby aplikaci používal a otevřel třeba další dialog k zadávání.

Obslužná metoda tlačítka odebratButton bude vypadat takto:

private void odebratButton_Click(object sender, EventArgs e)
{
        if (osobyListBox.SelectedItem != null)
        {
                spravceOsob.Odeber((Osoba)osobyListBox.SelectedItem);
        }
}

Důležitá je podmínka, která zjišťuje, zda je v ListBoxu vybraná nějaká položka. Jak vidíte, k vybrané položce se dostaneme přes vlastnost SelectedItem. Položku následně přetypujeme na Osoba, jelikož je typu object (to aby byl ListBox univerzální). Tuto osobu předáme metodě Odeber() na správci, která dále vykoná fyzické odebrání z listu.

Aplikaci si nyní můžete vyzkoušet, již půjde přidávat a odebírat osoby. Přidané osoby se ihned objeví v ListBoxu díky bindingům. ListBox vždy zobrazuje to, co vrací metoda ToString() objektu. U osob tedy zobrazuje jejich jméno. Pokud bychom chtěli zobrazit jinou vlastnost, zadáme její název do vlastnosti DisplayMember na ListBoxu (např. pro zobrazení narozenin tedy Narozeniny). Podobně fungují samozřejmě i další ovládací prvky, např. ComboBox.

Přidávání a odebírání
Nejbližší narozeniny

Do třídy hlavního formuláře si přidáme pomocnou privátní metodu ObnovNejblizsi(), která obnoví popisek s nejbližšími narozeninami.

private void ObnovNejblizsi()
{
        if (spravceOsob.Osoby.Count > 0)
        {
                Osoba nejblizsi = spravceOsob.NajdiNejblizsi();
                int vek = nejblizsi.SpoctiVek();
                if (DateTime.Today != nejblizsi.Narozeniny)
                        vek++;
                nejblizsiLabel.Text = nejblizsi.Jmeno + " (" + vek + " let) za " + nejblizsi.ZbyvaDni() + " dní";
        }
        else
                nejblizsiLabel.Text = "Žádné osoby v seznamu";
}

V případě, že jsou ve správci osob nějaké osoby, najdeme osobu s nejbližšími narozeninami. Získáme si věk této osoby a pokud nemá narozeniny právě dnes, přičteme k němu jedničku, aby se jednalo vždy o budoucí věk osoby. Do příslušného labelu poté poskládáme jméno osoby, do závorky její budoucí věk a kolik dní do narozenin zbývá.

V případě, že ve správci žádné osoby nemáme, zobrazíme o tom v labelu zprávu uživateli.

Metodu zavoláme na konci konstruktoru formuláře a také po přidání a odebrání osoby (na konci obslužných metod tlačítek, ale samozřejmě stále v podmínkách).

Detaily osoby

Shází nám již jen zobrazovat detaily vybrané osoby. Naklikneme si ListBox, čímž nám Visual Studio vygeneruje obslužnou metodu události SelectedIndexChanged (změna vybrané položky). Zde musíme opět zkontrolovat, zda je nějaká položka (osoba) vybraná. Pokud ano, načteme si jí a její vlastnosti zobrazíme v příslušných labelech a MonthCalendar nastavíme na její datum narození.

if (osobyListBox.SelectedItem != null)
{
        Osoba vybrana = (Osoba)osobyListBox.SelectedItem;
        narozeninyLabel.Text = vybrana.Narozeniny.ToLongDateString();
        vekLabel.Text = vybrana.SpoctiVek().ToString();
        narozenMonthCalendar.SelectionStart = vybrana.Narozeniny;
}

Aplikaci si můžete vyzkoušet.

Detaily výročí

V příští lekci, Upomínač narozenin - Ukládání dat a závěr, dokončíme ukládání a načítání dat z/do souboru. Dosavadní zdrojové kódy jsou vám jako vždy k dispozici níže. Pokud jste se někde zasekli, najděte si chybu.


 

Stáhnout

Staženo 1157x (346.33 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
8 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (4)

 

 

Komentáře
Zobrazit starší komentáře (4)

Avatar
FoByCZ
Člen
Avatar
FoByCZ:20.7.2017 3:56

BindingList je v namespace System.Componen­tModel. Do hlavičky SpravceOsob.cs přidej:

using System.ComponentModel;
 
Odpovědět 20.7.2017 3:56
Avatar
Michal Štěpánek:20.7.2017 13:28

Když si na ta podtržená slova najedeš myší, ve většině případů ti VS nabídne řešení problému. Např. chybějící usingy...

Odpovědět 20.7.2017 13:28
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
maaartin2
Člen
Avatar
maaartin2:1.9.2017 12:05

Když se volá zobrazení nového okna pomocí ShowDialog(), viz:

OsobaForm osobaForm = new OsobaForm(sprav­ceOsob);
osobaForm.Show­Dialog();

nemělo by dojít ještě k zavolání metody Dispose() na osobaForm?
viz: https://msdn.microsoft.com/…vs.110).aspx

Co se vlastně stane v případě nezavolání metody Dispose(), když dojde zřejmě pouze ke schování formuláře?

 
Odpovědět 1.9.2017 12:05
Avatar
Leoš Dospěl:12.10.2017 14:11

Prosim Vás nevíte někdo proč je aplikace šedá a nejde ovládat? kod bych měl mít stejny. Díky

Editováno 12.10.2017 14:12
 
Odpovědět 12.10.2017 14:11
Avatar
David Draisaitl:28.10.2017 13:28

Ahoj, jména se mi nezobrazují v listBoxu, kde můžu hledat zdroj chyby ?
Díky.

 
Odpovědět 28.10.2017 13:28
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na David Draisaitl
David Čápka:28.10.2017 18:46

Prostě si stáhneš zdrojový kód pod článkem a porovnáš ho se svým?

Odpovědět 28.10.2017 18:46
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
Ondřej Sochor:10. ledna 17:55

ahoj, doufám že je diskuze stále i po letech aktivní - mám problém s propojením obou jmenných prostorů, konkrétně v bodě kdy se vytváří instance tedy:

private void pridatButton_Clic­k(object sender, EventArgs e)
{
OsobaForm osobaForm = new OsobaForm(sprav­ceOsob);
osobaForm.Show­Dialog();
}

červeně se mi podtrhne OsobaForm stím že chybí direktive using atd, pokud ale napíši Using WindowsFormsApp1 nebo using OsobaForm..(proste co mám v kolonce namespace v druhem souboru) tak to také nepmůže.

Bohužel mi ani nejde stáhnout zdroják(mám hodně starý počítač) a už si stím dost dlouho lámu hlavu takže bych byl opravdu vděčný kdyby mi někdo poradil, předem děkuji za odpověď :)

 
Odpovědět 10. ledna 17:55
Avatar
Odpovídá na Ondřej Sochor
Michal Štěpánek:11. ledna 9:33

a máš mezi usingy

using System.Windows.Forms;

?

Odpovědět 11. ledna 9:33
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Odpovídá na Michal Štěpánek
Ondřej Sochor:11. ledna 11:30

Právě že ano, kvůli tomu mi to příde tak divné

 
Odpovědět 11. ledna 11:30
Avatar
Odpovídá na Ondřej Sochor
Michal Štěpánek:11. ledna 11:33

Toto jsou usingy ze staženého příkladu

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

Skutečně se ti ten "OsobaForm" jmenuje takhle?

Odpovědět 11. ledna 11:33
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 14. Zobrazit vše