Tento díl se věnuje několika novým komponentám (TextBox, PasswordBox, CheckBox a Label) na příkladu jednoduchého přihlašovacího formuláře.
Před samotným návrhem se krátce podíváme na smysl nově probíraných komponent.
TextBox
TextBox slouží jako vstupní komponenta pro zadávání neformátovaného textu. Hodí se na širokou škálu případů jako vstupní pole jednořádkového i víceřádkového textu. V našem formuláři bude sloužit pro zadávání uživatelského jména.
Má široké možnosti nastavování chování textu uvnitř sebe. Lze volit způsob zalamování (TextWrapping), povolovat posuvníku obsahu (VerticalScrollBarVisibility, HorizontalScrollBarVisibility) a také, zda je vůbec možné vložit nový řádek (AcceptsReturn). Samozřejmě podporuje nastavování velikosti a typu písma, což jsem popsal v minulém díle.
Hodnotu lze číst nebo nastavit vlastností Text.
Na předchozím obrázku je defaultní nastavení TextBox komponenty pro jednořádkový vstup. Následující kód ukazuje, jak nastavit vlastnosti tak, aby bylo možné zadávat text s více řádky. Povoluje přidávání dalších řádků a aktivuje vertikální i horizontální posuvník:
<TextBox
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible"
AcceptsReturn="True" />
Poznámka: Pokud povolíte zalamování (TextWrapping="Wrap"), docílíte stejné funkčnosti, jako volba v poznámkovém bloku “Zalamovat řádky”. Text tak nikdy nepřeteče na šířku TextBox.
PasswordBox
PasswordBox je funkčně podobný jako TextBox. Slouží ke skrytému zadávání hesla. Možnosti nastavení proti TextBox jsou pochopitelně omezené (nepotřebujeme řešit zalamování textu a podobně).
Hodnotu hesla lze číst nebo nastavit vlastností Password.
CheckBox
CheckBox je jednoduchá vstupní komponenta, kterou lze vybrat jeden ze tří stavů (viz obrázek). Při běžné konfiguraci lze však volit pouze mezi možnostmi “Ano/Ne” (zaškrtnuto/nezaškrtnuto). Třetí stav je možné povolit vlastností IsThreeState = true.
Hodnotu lze číst nebo nastavit vlastností IsChecked. Ta může nabývat hodnotu true (zaškrtnuto), false (nezaškrtnuto) nebo případně null (ve Visual Basic Nothing; třetí stav).
Label
Label je pro mnoho lidí přecházejících z Windows Forms poněkud matoucí. Tam totiž slouží jako nejjednodušší komponenta pro zobrazení textu, o což se ve WPF stará TextBlock. Label je proti tomu ve WPF většinou vnitřně stejně interpretován jako TextBlock. Což mimo jiné znamená, že je v případě, pokud chcete pouze zobrazit text, lepší použít přímo TextBlock.
V překladu Label znamená “popisek”. Konkrétně v případě WPF se jedná o popisek k libovolné jiné komponentě, kterou je možné aktivovat (přenést focus) klávesovou zkratkou Alt+[klávesa]. Ona konkrétní klávesa se označuje jako tzv. access key (přístupová klávesa) a my ji identifikujeme uvedením symbolu “_” (podtržítko) před požadovaný znak v textu popisku.
Následující kód ukazuje, jak vytvořit Label s popiskem “Ukázkový Label:” (písmeno “k” je access key), který odkazuje na TextBox vedle něj.
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Label Content="U_kázkový Label:" Target="{Binding ElementName=textBox1}" />
<TextBox Width="200" Name="textBox1" />
</StackPanel>
Aby mohl Label fungovat, musí odkazovat na nějakou komponentu, kterou popisuje. K tomu slouží vlastnost Target. V příkladu jsem si cílový prvek pojmenoval vlastností Name jako “textBox1” a následně jsem použil výraz k vytvoření odkazu na pojmenovanou instanci komponenty:
{Binding ElementName=textBox1}
Použitý výraz nebudu nijak rozebírat, protože se výrazům budu věnovat v samostatných několika článcích.
Aplikace po stisknutí klávesy Alt zobrazí na všech elementech formuláře příslušné access keys a my tak jasně vidíme, že pro toto textové pole je klávesová zkratka Alt+k. Po jejím stisknutí se přenese focus na textové pole, což urychlí pohyb ve formuláři pomocí klávesnice.
Poznámka: Pokud chcete zobrazit v textu popisku podtržítko nepoužité jako access key, stačí jej zdvojit. Tedy “text_s_podtržítkem” zapište jako “text__s__podtržítkem”.
Návrh přihlašovacího formuláře
Nyní se vytvoříme jednoduchý formulář na přihlašování uživatelů. Funkčně nebude sice nic dělat, ale to v tuto chvíli není důležité. Bude vypadat takto:
Při vytváření chceme chtít dosáhnout těchto výsledků:
- Půjde zadat jméno uživatele, jeho heslo a bude k dispozici možnost zapamatovat přihlašovací údaje.
- Klávesa Enter dialog potvrdí a klávesa Escape naopak dialog uzavře.
- Klávesová zkratka Alt+… dovolí přeskočit na konkrétní pole.
- Při spuštění aplikace je aktivní pole pro zadávání uživatelského jména.
Krok 1. – Hlavní rozložení formuláře
Máme založený nový projekt typu WPF Application.
Hlavnímu formuláři (MainWindow) můžeme nastavit nadpis a změnit barvu pozadí:
- Nadpis: Title=”Přihlášení”
- Jako barvu pozadí jsem použil: Background="#FFE2E2E2"
Formulář dále rozdělíme do 3 základních částí (přesněji – řádků):
- Záhlaví – pro nadpis “Přihlášení k systému” – ten bude mít automatickou výšku podle svého obsahu.
- Obsah – tato část okna bude vyplňovat zbytek formuláře a bude se tak zvětšovat/zmenšovat při změně výšky celého formuláře.
- Zápatí – bude obsahovat tlačítka “Přihlásit” a “Storno” – stejně, jako záhlaví, bude mít výšku automatickou podle svého obsahu.
Výsledek může vypadat následovně (vložil jsem obarvené TextBlock elementy jako dočasnou výplň pro lepší představu):
Rozdělení na tyto řádky můžeme snadno provést elementem Grid:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Background="LightGreen" Text="Nadpis" FontSize="20" />
<TextBlock Background="LightBlue" Text="Obsah" FontSize="20" Grid.Row="1" />
<TextBlock Background="LightYellow" Text="Zápatí" FontSize="20" Grid.Row="2" />
</Grid>
Krok 2. – Nadpis a tlačítka v zápatí
V dalším kroku vyplníme první a poslední řádek. Nejprve nadpis:
<TextBlock Text="Přihlášení k systému" Margin="10" FontSize="20" />
Nadpis je tak větším písmem (velikost 20) a s odsazením 10 device-independent-pixels. Protože se jedná o první řádek Gridu (tedy index 0), nemusíme uvádět Grid.Row=”0”.
Dále vložíme tlačítka do spodní lišty. Seřazené budou vedle sebe a proto můžeme použít StackPanel:
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="2">
<Button Content="Přihlásit" Width="100" Margin="0 0 20 0" IsDefault="True" />
<Button Content="Storno" Width="100" IsCancel="True" />
</StackPanel>
Nejprve jsem umístil StackPanel do spodního řádku (Grid.Row=”2”) a pro zarovnání k pravému okraji jsem nastavil HorizontalAlignment=”Right”.
Uvnitř StackPanelu se nachází tlačítka “Přihlásit” a “Storno”. Použil jsem u nich navíc tyto dvě vlastnosti:
- IsDefault=”True” – označuje tlačítko na formuláři jako defaultní, které bude stisknuto klávesou Enter
- IsCancel=”True” – označuje tlačítko na formuláři jako storno, které bude stisknuto klávesou Escape
Jako drobnou kosmetickou úpravu jsem přidal jednomu z tlačítek odsazení pravého okraje (Margin=”0 0 20 0”). Díku tomu není na druhé tlačítko přímo nalepené, ale vytváří mezi sebou mezeru.
Formulář vypadá následovně. Všimněte si podbarveného defaultního tlačítka “Přihlásit”, které se vyvolá při stisknutí Enter.
Krok 3. – Layout vstupních ovládacích prvků
Nyní nás čeká vložení jednotlivých vstupních komponent pro jméno, heslo a potvrzení, zda přihlašovací údaje uložit.
Pro tento účel využijeme další vnořený Grid. Ten bude umístěný uvnitř prostředního řádku hlavního Gridu (Grid.Row=”1”).
Vnitřek rozdělíme na 3 řádky (pro každý vstup jeden) a 2 sloupce (první sloupec popis hodnoty a druhý na vstupní prvek). Sloupce budou na šířku nastavené poměrem 1:2, protože působí lépe, pokud je více místa pro vstupní prvky.
A nakonec celý Grid vycentrujeme vertikálně na střed vlastností VerticalAlignment=”Center”. Kód definice vypadá následovně:
<Grid Grid.Row="1" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
</Grid>
Do Gridu následně přidáme popisky a jednotlivá pole:
<Label Content="_Uživatelské jméno:" VerticalAlignment="Center" Target="{Binding ElementName=txtUserName}" />
<Label Content="_Heslo:" Grid.Row="1" VerticalAlignment="Center" Target="{Binding ElementName=txtPassword}" />
<TextBox Grid.Column="1" Margin="10" Padding="4" Name="txtUserName" />
<PasswordBox Grid.Column="1" Grid.Row="1" Margin="10" Padding="4" Name="txtPassword" />
<CheckBox Content="_Zapamatovat přihlášení" Grid.Row="2" Grid.Column="1" Margin="10" Name="cbxRememberCredentials" />
Výsledek bude vypadat takto:
Vyzkoušejte si, že při stisknutí access keys se aktivují příslušné komponenty (Alt+U = uživatelské jméno, Alt+H = heslo, Alt+Z = zapamatovat přihlášení).
Krok 4. – Dolaďování, focus a funkční kód
Aktuální podoba formuláře má všechny prvky nalepené na okrajích. To můžeme snadno vyřešit nastavením vlastnosti okrajů Margin hlavnímu Gridu, který nese všechny komponenty na formuláři. Řekněme na hodnotu 10. Výsledek na následujícím obrázku je patrný.
Dále bude vhodné zobrazit přihlašovací formulář na středu obrazovky, čehož dosáhneme pomocí vlastnosti: WindowStartupLocation="CenterScreen".
Také lze zamezit zvětšování nebo zmenšování formuláře pomocí vlastnosti ResizeMode="NoResize". Avšak pro testování můžete ponechat režim výchozí, tedy dovolující změnu velikosti.
Možná je matoucí, proč se připravoval dynamický layout, když bude zvětšování a zmenšování zakázané. První důvod je samozřejmě to, že považuji za důležité se dynamické pozicování naučit. A druhým důvodem je fakt, že formulář můžete někdy potřebovat předělávat. A čím větší je, tím hůře se upravuje, pokud je layout absolutně pozicovaný. Představte si, že máte svoji komponentu použitou na 50ti místech v aplikaci. Změnit její velikost v případě absolutního pozicování znamená upravit všech 50 míst, kde se nachází. Oproti tomu u dynamického pozicování máte nemalou šanci, že velká část vaší aplikace nebude manuální úpravy vůbec potřebovat, protože pozicování nepočítalo s fixní velikostí komponenty.
Dále chceme, aby aplikace při spuštění měla kurzor připravený v poli zadávání uživatelského jména. Toho lze docílit nastavením výchozího prvku do vlastnosti “FocusManager.FocusedElement” nad celým formulářem, kde uvedeme odkaz na vstupní pole pomocí výrazu podobně, jako je tomu u Label komponenty:
FocusManager.FocusedElement="{Binding ElementName=txtUserName}"
Jako finální úpravu můžeme přidat do tlačítek nějaký funkční kód, abychom ověřili funkčnost kláves Enter a Escape. Do tlačítka “Storno” vložte kód pro ukončení aplikace:
Application.Current.Shutdown();
A do tlačítka “Přihlásit” kód pro zobrazení informativní zprávy:
MessageBox.Show("Přihlášení.");
Nyní by okno mělo splňovat všechny původní požadavky.
Pro úplnost uvádím i kód celého okna. Pokud jej budete kopírovat, nezapomeňte přejmenovat jméno třídy (x:Class vlastnost úplně na začátku), pokud se váš projekt jmenuje jinak, než WpfApplication1.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Přihlášení" Height="312" Width="525"
FocusManager.FocusedElement="{Binding ElementName=txtUserName}" Background="#FFE2E2E2"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="Přihlášení k systému" Margin="10" FontSize="20" />
<Grid Grid.Row="1" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Content="_Uživatelské jméno:" VerticalAlignment="Center" Target="{Binding ElementName=txtUserName}" />
<Label Content="_Heslo:" Grid.Row="1" VerticalAlignment="Center" Target="{Binding ElementName=txtPassword}" />
<TextBox Grid.Column="1" Margin="10" Padding="4" Name="txtUserName" />
<PasswordBox Grid.Column="1" Grid.Row="1" Margin="10" Padding="4" Name="txtPassword" />
<CheckBox Content="_Zapamatovat přihlášení" Grid.Row="2" Grid.Column="1" Margin="10" Name="cbxRememberCredentials" />
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="2">
<Button Content="Přihlásit" Width="100" Margin="0 0 20 0" IsDefault="True" Click="Button_Click_2" />
<Button Content="Storno" Width="100" IsCancel="True" Click="Button_Click_1" />
</StackPanel>
</Grid>
</Window>
Závěr
Tento díl by měl ověřit vaše znalosti z předchozích článků. Pokud budete mít jakékoliv konstruktivní připomínky nebo dotazy, neváhejte je vkládat do diskuse pod článkem.