Teorie: Popis základních kontrolek na WPF formuláři
(Dílčí příklady jsou převzaty z https://wpf-tutorial.com/ )
Jakým způsobem se pracuje s jednotlivými kontrolkami bylo vysvětleno u prvního příkladu v rámci cvičení. Doporučujeme se nejprve podívat na tento příklad.
4. Panely
4.1. Grid
Grid (mřížka) je nejčastěji používaný nástroj pro řešení layoutu (rozložení) okna. Tento panel je dokonce automaticky generován na každé nové okno. Nabízí mřížku, kterou lze pomocí různých strategií rozdělit na řádky a sloupce tak, aby okno vypadalo dobře v různých velikostech (potažmo rozlišeních obrazovky). Při troše snahy se pak obsah vykreslovaný do okna proporčně přizpůsobuje při změně velikosti okna např. myší.
Podívejme se nejprve na základní problém. Když napíšeme následující kód:
<Window x:Class="WpfTutorialSamples.Panels.Grid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Grid" Height="300" Width="300">
<Grid>
<Button>Button 1</Button>
<Button>Button 2</Button>
</Grid>
</Window>
bude výsledek vypadat takto:
Obě tlačítka budou zobrazena přes sebe.
Pokud bychom chtěli zobrazit obě tlačítka vedle sebe, mohli bychom například zkusit následující možnost:
<Button Width="150" HorizontalAlignment="Left">Button 1</Button>
<Button Margin="150,0,0,0">Button 2</Button>
To samozřejmě zobrazí tlačítka vedle sebe, ale vše bude fungovat jen pro formulář o velikost 300x300 pixelů. Levé tlačítko si bude „držet“ šířku 150 pixelů i po zvětšení formuláře a pravé pak bude vždy vzdálené přesně 150 pixelů od levého okraje.
Co kdybychom však chtěli okno „rozpůlit“ shora-dolů a stanovit, že v levé části bude jedno tlačítko a v pravé druhé, tak, aby vše fungovalo pro libovolnou velikost okna. Zde je nutné použít právě Grid – mřížku. Definice je na první pohled poněkud obtížnější. S jejím častějším využíváním však poznáme její jednoduchost.
Ukažme si vše na zmíněném příkladu. Chceme „rozpůlit“ okno a v levé části zobrazit jedno tlačítko a v pravé druhé tlačítko.
<Window x:Class="WpfTutorialSamples.Panels.Grid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Grid" Height="300" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
</Grid>
</Window>
Takto vytvořený layout bude fungovat nezávisle na velikosti okna. Popišme si tento zápis:
- Grid obsahuje nejdůležitější vlastnosti ColumnDefinition a RowDefinitions, pomocí kterých se definují vlastnosti řádků a sloupců. Tato vlastnost je typu kolekce, je nutné ji tedy definovat pomocí tečkové notace (Grid.ColumnDefinition).
- Jakmile jsou definovány řádky a sloupce, je možné mezi značky <Grid> a </Grid> vložit kontrolky (nebo jiné panely – vnořený Grid, WrapPanel, StackPanel). U každé vložené kontrolky, nebo panelu, je možné nově přidat vlastnost:
- Grid.Column – v jakém sloupečku se má kontrolka nacházet
- Grid.Row – v jakém řádku se má kontrolka nacházet
- Číslování řádků a sloupců začíná 0. Grid.Column=“0“ nebo Grid.Row=“0“ není potřeba psát, neboť 0 je výchozí hodnota. Pokud u kontrolky není uveden ani Grid.Column a ani Grid.Row automaticky se předpokládá, že má být kontrolka umístěna v první buňce horní zleva.
Pozastavme se ještě u ColumnDefinition a RowDefinition. Ukažme si příklad, kde jsou předvedeny řádky i sloupce:
<Window x:Class="WpfTutorialSamples.Panels.TabularGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TabularGrid" Height="300" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
<Button Grid.Column="2">Button 3</Button>
<Button Grid.Row="1">Button 4</Button>
<Button Grid.Column="1" Grid.Row="1">Button 5</Button>
<Button Grid.Column="2" Grid.Row="1">Button 6</Button>
<Button Grid.Row="2">Button 7</Button>
<Button Grid.Column="1" Grid.Row="2">Button 8</Button>
<Button Grid.Column="2" Grid.Row="2">Button 9</Button>
</Grid>
</Window>
Zde vidíme, jak je možné řádky a sloupce vzájemně kombinovat. Zajímavá je zejména * u vlastnosti Width-šířka u ColumnDefinition resp. RowDefinition (zde vlastnost Height-výška). Ta značí tzv. poměrové uspořádání. V tomto případě jsou řádky i sloupce v poměru: 2*, 1*, 1*. V obecné mluvě bychom spíše napsali v poměru 2:1:1. To znamená, že si rozdělíme formulář na 4 stejné dílky a poměrově je rozdělíme. V případě, kdy je formulář široký 200 pixelů, bude jeden dílek představovat 50 pixelů, tj. první sloupec bude široký 100 pixelů a další dva po 50 pixelech (v případě tohoto příkladu to platí i pro řádky).
Šířku i výšku v rámci panelu Grid je možné definovat třemi způsoby:
- Absolutně – uvedení celého čísla. To znamená počet pixelů na řádek nebo sloupec
- Poměrově – číslo a hvězdička (např. 4*). To je právě ukázané poměrové uspořádání. Je výhodné vždy na formuláři mít v tomto uspořádání alespoň jednu řádku a jeden sloupec.
- Automaticky (Auto) – výška řádku nebo šířka sloupce je stanovena dle obsahu
Ukažme si opět příklad:
<Window x:Class="WpfTutorialSamples.Panels.GridUnits"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridUnits" Height="200" Width="400">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2 with long text</Button>
<Button Grid.Column="2">Button 3</Button>
</Grid>
</Window>
Zde vidíme všechny možnosti nastavení šířky sloupce (výška řádku se nastavuje stejně). Třetí sloupec, který má nastavenou šířku 100 pixelů si ji bude držet za všech okolností. Šířka tlačítka 2 ve druhém sloupci je určena textem uvnitř tlačítka. Text můžeme samozřejmě v programu změnit – pak se bude měnit i šířka druhého sloupce. První sloupec vyplní zbývající plochu okna.
Je přípustné (a také velmi využívané), aby byla kontrolka roztažena přes více buněk (analogie – slučování buněk v Excelu). Ukažme si princip na příkladu, kde chceme, aby v prvním řádku byla dvě tlačítka a v druhém jen jedno:
<Window x:Class="WpfTutorialSamples.Panels.GridColRowSpan"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridColRowSpan" Height="110" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
<Button Grid.Row="1" Grid.ColumnSpan="2">Button 3</Button>
</Grid>
</Window>
Vše je zařízeno pomocí vlastnosti Grid.ColumnSpan, kde je definováno kolik buněk v rámci sloupců chceme spojit. Obdobně funguje i vlastnost Grid.RowSpan. Obojí lze samozřejmě kombinovat.