8. díl - Upomínač narozenin v C# .NET WPF - Propojení vrstev

C# .NET WPF Upomínač narozenin v C# .NET WPF - Propojení vrstev American English version English version

V minulém dílu našeho seriálu tutoriálů o tvorbě okenních aplikací v C# .NET WPF jsme naprogramovali většinu logické vrstvy aplikace. Dnes 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 vyhazovat 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 dílech seriálu, 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 její metody bychom z formuláře pouze volali. XAML a i jeho CodeBehind je tedy stále prezentační vrstva aplikace. XAML definuje jak formulář vypadá, CodeBehind volá logiku, kterou neobsahuje.

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

Propojení prezentace a logiky

Přejdeme do CodeBehind formuláře MainWindow 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.

Přidává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 OsobaWindow, 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 OsobaWindow(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 DatePickeru přistoupíme pomocí vlastnosti SelectedDate, která je nullovatelného typu DateTime?.

Určitě si vzpomínáte, že metoda Pridej() vyvolá výjimku v případě příliš krátkého jména, nullového data 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, RoutedEventArgs e)
{
        try
        {
                spravceOsob.Pridej(jmenoTextBox.Text, narozeninyDatePicker.SelectedDate);
                Close();
        }
        catch (Exception ex)
        {
                MessageBox.Show(ex.Message, "Chyba", MessageBoxButton.OK, MessageBoxImage.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 MainWindow, tentokrát do grafického návrháře. Naklikneme tlačítko pridatButton a jeho obslužnou metodu upravíme takto:

private void pridatButton_Click(object sender, RoutedEventArgs e)
{
        OsobaWindow osobaWindow = new OsobaWindow(spravceOsob);
        osobaWindow.ShowDialog();
}

V obslužné metodě tlačítka pridatButton() vytvoříme novou instanci formuláře OsobaWindow, 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 dialogů se toto většinou dělá (dialogy rozumějte pomocné formuláře, který slouží nejčastěji k zadání dat). 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í.

Když bychom aplikaci nyní spustili, osobu bychom sice přidali do ObservableCollec­tion, nicméně bychom ji v ListBoxu neviděli. Je to samozřejmě z toho důvodu, že ListBox není na tuto kolekci napojený. Jistě vás nepřekvapí, že toho docílíme pomocí Bindingu.

Binding

Pokud chceme bindovat, musíme oknu nejprve nastavit tzv. kontext. To je objekt, jehož vlastnosti budeme bindovat. To uděláme nejjednodušeji v konstruktoru okna pomocí následujícího kódu:

DataContext = spravceOsob;

Instance správce osob je nyní nastavena jako datový kontext hlavního okna a my v tomto okně můžeme zobrazovat její vlastnosti.

Přesuneme se do XAMLu a ListBoxu dodáme atribut ItemsSource:

<ListBox Name="osobyListBox" Grid.Column="0" Grid.Row="2" Margin="0, 0, 0, 10" ItemsSource="{Binding Osoby}"/>

Tím říkáme, že zdrojem položek ListBoxu je vlastnost Osoby na kontextu, kterým je správce osob.

Zkuste si aplikaci spustit a přidat nějaké osoby. Přidané osoby se ihned objeví v ListBoxu díky bindingům. ListBox vždy zobrazuje to, co vrací metoda ToString() jeho položek. U osob tedy zobrazuje jejich jméno. Podobně fungují samozřejmě i další kontrolky, např. ComboBox.

Binding u WPF ListBoxu v C# .NET
Odebrání uživatelů

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

private void odebratButton_Click(object sender, RoutedEventArgs 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 Osobu, 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 ObservableCollec­tion.

Dnešní projekt je níže ke stažení a já se na vás těším příště, kdy budeme pokračovat v bindingu.


 

Stáhnout

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

 

  Aktivity (3)

Článek pro vás napsal David Čápka
Avatar
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 se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (4 hlasů) :
4.254.254.254.25 4.25


 



 

 

Komentáře

Avatar
vrsek.daniel
Člen
Avatar
vrsek.daniel:

Dostal som sa k takému problému že keď si pridám osobu do toho zoznamu že mi ju pridá do itemnou ale nezobrazuje mi ju tam mám okontrolované že medzi itemami existujú všetky čo som zadal ale nezobrazuje sa mi v listbox-e ale ak si priradím nejakú osobu do správcu v konštruktore tak mi to hodí aj zobrazí nevieš kde by mohla byť chyba?

 
Odpovědět  +1 19.1.2014 19:09
Avatar
Petr Čech (czubehead):

Dá se na binding nastavit i statická třída?

Odpovědět 20.1.2014 20:02
Why so serious? -Joker
Avatar
Odpovědět  +2 21.2.2014 22:00
Nesnáším {}, proto se jim vyhýbám.
Avatar
honza.bilek4
Člen
Avatar
honza.bilek4:

Poslupoval jsem podle návodu,ale háže mi to chybu:

Error 1 Inconsistent accessibility: parameter type 'UpominacNar.Sprav­ceOsob' is less accessible than method 'UpominacNar.O­sobaWindow.Oso­baWindow(Upomi­nacNar.Spravce­Osob)' C:\Users\Jan\do­cuments\visual studio 2012\Projects\U­pominacNar\Oso­baWindow.xaml­.cs 24 16 UpominacNar

Kde může být problém?

 
Odpovědět 30.4.2014 13:53
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na honza.bilek4
Jan Vargovský:

Že třída SpravceOsob je internal (máš tam class Spravce Osob { ... }) a využíváš to někde v public třídě (OsobaWindow)

Editováno 30.4.2014 14:42
 
Odpovědět 30.4.2014 14:40
Avatar
honza.bilek4
Člen
Avatar
Odpovídá na Jan Vargovský
honza.bilek4:

Paráda,už mi to došlo,díky.

 
Odpovědět 30.4.2014 18:27
Avatar
ja
Člen
Avatar
ja:

dík

 
Odpovědět 15.6.2015 13:10
Avatar
Michal Gros
Redaktor
Avatar
Odpovídá na Jan Vargovský
Michal Gros :

no ja nechapu co stím ?:
mám stejný problem
Severity Code Description Project File Line Suppression State
Error CS0051 Inconsistent accessibility: parameter type 'SpravceOsob' is less accessible than method 'OsobaWindow.O­sobaWindow(Sprav­ceOsob)' pripominacNarozenin C:\Users\Michal\O­neDrive\visual_stu­dio\pripominac­Narozenin\pri­pominacNaroze­nin\OsobaWindow­.xaml.cs 23 Active

Odpovědět 20.12.2015 19:57
Jestli jste dobří nahrnou na Vás spoustu práce. Jestli jste sakra dobří, tak se jí dokážete zbavit.
Avatar
Michal Gros
Redaktor
Avatar
Michal Gros :
private SpravceOsob spravceOsob;

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

nějako mi to nefunguje nevím co s tím
Hlásí mi to chybu

Severity Code Description Project File Line Suppression State
Error CS0051 Inconsistent accessibility: parameter type 'SpravceOsob' is less accessible than method 'OsobaWindow.O­sobaWindow(Sprav­ceOsob)' pripominacNarozenin C:\Users\Michal\O­neDrive\visual_stu­dio\pripominac­Narozenin\pri­pominacNaroze­nin\OsobaWindow­.xaml.cs 23 Active

Odpovědět 20.12.2015 19:59
Jestli jste dobří nahrnou na Vás spoustu práce. Jestli jste sakra dobří, tak se jí dokážete zbavit.
Avatar
Odpovídá na Michal Gros
Michal Štěpánek:

a máš třídu SpravceOsob nastavenou jako "Public"?

Odpovědět 20.12.2015 20: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 10.