6. díl - Upomínač narozenin v C# .NET WPF - Návrh oken

C# .NET WPF Upomínač narozenin v C# .NET WPF - Návrh oken 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 doprogramovali jednoduchou kalkulačku. Během následujících několika článků si vytvoříme středně pokročilou aplikaci. Bude se jednat o upomínač narozenin přátel. Hotová aplikace bude vypadat takto:

Upomínač narozeniny v C# .NET WPF

Vidíme, že aplikace má 2 formuláře, používá kontrolky pro práci s datem a také obsahuje ukládání dat do souborů. Vnitřně narazíme na architekturu Model-ViewModel, výjimky a bindingy. Nebude toho málo, ale vše si postupně vysvětlíme a jistě to zvládnete. Aplikace je ještě poměrně jednoduchá a věřím, že nejlépe se látka naučí na praktickém příkladu.

Návrh formulářů

Začněme tradičně návrhem formulářů. Vytvořte si nový WPF projekt s názvem UpominacNarozenin.

Hlavní formulář

Formuláři nastavte titulek okna, startovní pozici na obrazovce a můžete i nějakou ikonku.

Rozložení

Možností jak dospět toho samého výsledků při rozložení formuláře je více. My si jeho Grid rozdělíme následujícím způsobem:

Grid okna v C# .NET WPF

Tabulka má 2 sloupce a 4 řádky. Řádky jsou vysoké postupně: 20, 30, * a 30 DIP. Ten předposlední se tedy roztahuje s oknem. Levý sloupec má šířku *, pravý má pevnou šířku 200 DIP. Kolem celého Gridu je Margin 10 DIP. Kód Gridu vypadá nyní následovně:

<Grid Margin="10">
        <Grid.RowDefinitions>
                <RowDefinition Height="20"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
</Grid>
Horní TextBlocky

V prvních dvou řádcích Gridu jsou vložené TextBlocky s informací o dnešním datu a nejbližších narozeninách. Text se zde skládá z několika částí a ačkoli lze v každém řádku použít pouze jeden TextBlock, do kterého hodnotu složíme, my si pro zjednodušení vložíme několik TextBlocků vedle sebe.

StackPanel

Pro skládání kontrolek vedle sebe nebo pod sebe slouží StackPanel. Jedná se o kontejner na další kontrolky, stejně jako Grid. Do každého řádku tabulky vložíme jeden StackPanel. Budeme chtít, aby se StackPanel nevložil pouze do prvního sloupce, ale zasahoval do celého řádku. Proto mu zadáme atribut ColumnSpan s hodnotou 2, což znamená, že zasahuje přes 2 sloupce. Je to podobné jako colspan v HTML nebo jako když spojujete buňky tabulky v Excelu. Stejně tak existuje RowSpan, který vkládá element přes více řádků. StackPanelům ještě nastavíme atribut Orientation na hodnotu Horizontal, výchozí je totiž Vertical, tedy řazení pod sebe. Rovnou do nich také vložíme jednotlivé TextBlocky, text těch, kde se mají zobrazovat data, ponecháme zatím prázdný.

<StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Orientation="Horizontal">
        <TextBlock Text="Dnes je "/>
        <TextBlock Text="" />
</StackPanel>

<StackPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal">
        <TextBlock Text="Nejbližší narozeniny má "/>
        <TextBlock Text=""/>
        <TextBlock Text=" za "/>
        <TextBlock Text=""/>
        <TextBlock Text=" dní."/>
</StackPanel>
Spodní tlačítka

Úplně stejným způsobem vložíme do posledního řádku okna dvě tlačítka. Opět budou ve StackPanelu (protože je chceme vedle sebe) a ten bude opět zasahovat přes 2 sloupce. StackPanel se bude centrovat. Tlačítkům rovnou přiřadíme jména, jelikož je budeme používat v CodeBehind. Levému nastavíme pravý Margin, aby nebyla nalepená úplně na sobě.

<StackPanel Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center">
        <Button Width="100" Margin="0,0,10,0" Name="pridatButton" Content="Přidat"/>
        <Button Width="100" Name="odebratButton" Content="Odebrat"/>
</StackPanel>

Váš formulář by měl nyní vypadat asi takto:

StackPanely v C# .NET WPF

Můžete si aplikaci zkusit spustit a okno rozšířit, abyste zkontrolovali, zda se vše přizpůsobuje.

ListBox

Uložené osoby budeme zobrazovat v kontrolce ListBox. Jak již název napovídá, jedná se o nějaký seznam položek. ListBox je v podstatě rozbalený ComboBox, pracuje se s ním úplně stejně. V našem případě nebudeme položky definovat v XAMLu, ale načteme je později z logické vrstvy aplikace. ListBox vložíme do 1. sloupce a 3. řádku, pojmenujeme ho osobyListBox a nastavíme mu spodní Margin na 10 DIP.

<ListBox Name="osobyListBox" Grid.Column="0" Grid.Row="2" Margin="0, 0, 0, 10"/>
Kalendář

Zbývá vložit jen kalendář a nad něj opět několik TextBlocků. Můžeme si v dané buňce buď udělat další Grid nebo použít StackPanel, který je na řazení kontrolek pod sebe dělaný. Tomu nastavíme levý Margin na 10 DIP. V každém řádku opět potřebujeme 2 TextBlocky vedle sebe, budou tedy v dalších StackPanelech. Kalendář vložíme jako kontrolku Calendar, slouží sice spíše pro výběr data, ale my ji budeme používat pro jeho zobrazení.

<StackPanel Grid.Column="1" Grid.Row="2" Margin="10, 0, 0, 0">
        <StackPanel Orientation="Horizontal">
                <TextBlock Text="Narozeniny: "/>
                <TextBlock Text="" />
        </StackPanel>
        <StackPanel Orientation="Horizontal">
                <TextBlock Text="Věk: "/>
                <TextBlock Text="" />
        </StackPanel>
        <Calendar Name="narozenCalendar" />
</StackPanel>

Hlavní formulář máme hotový.

Dialog pro přidání osoby

K projektu přidáme nové okno (klinutí pravým na projekt v Solution Exploreru -> Add -> Window), které pojmenujeme OsobaWindow. Opět si nastavte titulek, startovní pozici a ikonku.

Ukažme si znovu obrázek hotových formulářů, nyní pracujeme na tom vpravo:

Upomínač narozeniny v C# .NET WPF
Rozložení

Grid rozdělíme opět na 2 sloupce a 4 řádky. Výšky řádků jsou následující: 4*, 30, 30, *. První a poslední řádek se tedy roztahují s oknem, první zabere 4x více prostoru než poslední. Oba sloupce budou mít šířku *, ta je výchozí, nemusíme ji tedy ani definovat. Okolo celého Gridu necháme opět Margin 10. Výsledek vypadá takto:

Grid okna v C# .NET WPF

A jeho kód:

<Grid Margin="10">
        <Grid.RowDefinitions>
                <RowDefinition Height="4*"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
        </Grid.ColumnDefinitions>
</Grid>
Image

Do prvního řádku vložíme nějaký obrázek, abychom se s nimi naučili pracovat. Spoustu ikon volně ke stažení naleznete na webu http://www.iconfinder.com, vždy si přečtěte licenci pro jaké případy můžete danou ikonu používat. Obrázek vložíme pomocí kontrolky Image. Soubor obrázku (nejčastěji png) musíme podobně jako ikonu nejprve přidat do projektu. Poté název souboru uvedeme v atributu Source kontrolky Image. Když máme obrázků v projektu již hodně, vyplatí se na ně vytvořit nějakou složku. Výchozí chování obrázků je, že se roztahují tak, aby vyplnily rodičovskou kontrolku. To nám zde nevyhovuje a proto nastavíme Stretch na hodnotu "None". Obrázek vložíme do celého řádku tabulky pomocí ColumnSpan.

<Image Source="osoba_pridat.png" Stretch="None" Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="0"/>
Label

Do druhého sloupce dalších dvou řádků přijdou kontrolky k zadání jména a data narození. Ke každé kontrolce umístíme do prvního sloupce popisek. Nepoužijeme k tomu však TextBlock, ale Label. Label je popisek, který se vztahuje k určité kontrolce. Pokud do textu jeho popisku vložíme podtržítko před nějaké písmeno, definujeme tak klávesovou zkratku. Po stisknutí ALT + tohoto písmena se zaktivní kontrolka, ke které popisek patří. Pokud vás napadlo, jak v textu Labelu tedy zapsat podtržítko, napíšete dvě za sebou.

K zadání jména použijeme samozřejmě TextBox. K zadání data narození použijeme kontrolku DatePicker. Ukažme si kód:

<Label Content="_Jméno" Grid.Column="0" Grid.Row="1" Target="{Binding ElementName=jmenoTextBox}"/>
<Label Content="_Datum narození" Grid.Column="0" Grid.Row="2" Target="{Binding ElementName=narozeninyDatePicker}"/>
<TextBox Grid.Column="1" Grid.Row="1" Name="jmenoTextBox" Margin="0,0,0,5"/>
<DatePicker Grid.Column="1" Grid.Row="2" Name="narozeninyDatePicker" Margin="0,0,0,5"/>

Vidíme, že propojení Labelu s kontrolkou je realizované pomocí atributu Target. Zde je výraz ve složených závorkách, který začíná slovem Binding. Binding označuje provázání, zde Labelu na kontrolku s určitým jménem. Setkáme se s ním ještě na mnoha místech. Zbytek kódu by neměl být nic nového. Nyní ještě nemůžeme formulář ve spuštěné aplikaci zobrazit, ale až to půjde a stisknete na něm ALT + J, zaktivní se pole se jménem. ALT + D zaktivní DatePicker.

Dialog dokončíme vložením potvrzovacího tlačítka. To se bude zobrazovat dole ve středu posledního řádku.

<Button Name="okButton" Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Bottom" Width="100" Content="OK"/>

Každému oknu můžeme ve WPF ještě přiřadit co mají dělat výchozí a ukončovací klávesy. Výchozí klávesa je Enter a měla by vyvolat stisk tlačítka OK. Ukončovací klávesa je Escape. Proto tlačítku přidáme ještě atribut:

IsDefault="True"

Pokud bychom chtěli, aby se dialog zavřel stisknutím Escape, nejjednodušší je přidat Zavírací tlačítko a tomu nastavit atribut IsCancel na True.

Tak a máme hotovo. Myslím, že jste si užili navrhování formulářů v XAMLu do sytosti naučili se zas něco nového. Příště to bude čistě o logické části aplikace a C# kódu. Navržený formulář je jako vždy ke stažení níže.


 

Stáhnout

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

 

  Aktivity (4)

Č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 (7 hlasů) :
4.714294.714294.714294.714294.71429


 



 

 

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

Avatar
Michal Štěpánek:

jak špatně?

Odpovědět 20.12.2015 19:37
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Lukáš Hypša:

V "Dialog přidání okna" máš v "Rozložení" špatnej obrázek.

Odpovědět 10. března 17:04
I když se programování učím jenom z interetu, velmi mě baví a doufám, že se tím jednou budu i živit.
Avatar
krepsy3
Redaktor
Avatar
krepsy3:

Ahoj, Zkusil jsem label natargetovat na Checkbox, a v ten moment mi přestalo jít kliknout na ten checkbox, šlo to pouze přes tu klávesu označenou podtržítem, což je dost nepraktické, protože v té mé aplikaci se to týká odděděného Childa UserControlu, kterých tam mám více. Co s tím?

Odpovědět 7. května 22:00
Programátor je stroj k převodu kávy na kód.
Avatar
Odpovídá na krepsy3
Michal Štěpánek:

Co myslíš tím

label natargetovat na Checkbox

?

Odpovědět 8. května 9:40
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
krepsy3
Redaktor
Avatar
Odpovídá na Michal Štěpánek
krepsy3:

Přesně podle tutoriálu:

<Label Target="{Binding ElementName=isColorCheckbox}" Content="_Color"  />
<CheckBox Name="isColorCheckbox" />

Btw. dělá mi to i u ostatních kontrolek na tomtéž formuláři. Když Binding odmažu, funguje vše normálně. Možná pomůže informace, že tento formulář mám jako UserControl (Jméno je Pot.xaml), který do hlavního formuláře dědím přes

kontrolkaNaHlavnímPanelu.Children.Add(new Pot())
Odpovědět 8. května 14:53
Programátor je stroj k převodu kávy na kód.
Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:

Jo, byl tam 2x ten samý, už jsem to opravil :)

Odpovědět  +1 10. srpna 16:24
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
René Češka:

Vyřešil jsi to nějak? Mám úplně stejný problém jenom s tím rozdílem že mám Visual studio comunity 2015.

 
Odpovědět 10. září 23:14
Avatar
Gabriel Mastný
Redaktor
Avatar
Odpovídá na René Češka
Gabriel Mastný:

Jj, problém byl v tom že jsem zakládal projekt, který pracoval nejvýš s .NET frameworkem 3 a Calendar je přidaný až od 4.0...

Odpovědět 11. září 0:06
Where there's will, there's way.
Avatar
Odpovídá na Gabriel Mastný
René Češka:

Dík, a dá se nějak přenastavit framework v už založeném pojektu?

 
Odpovědět 11. září 8:27
Avatar
René Češka:

Sorry blbá otázka stačily mi 3 vteřiny googlení a než sem si to uvědomil a otestoval tak mi ten koment už nešel smazat.

 
Odpovědět 11. září 8:35
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 26. Zobrazit vše