Nástroje pro tvorbu layoutu v Silverlightu 2.0 a Silverlight toolkitu

V tomto díle se vrátíme k úplným základům Silverlightu. Ukážeme si čtyři nástroje sloužící k tvorbě layoutu, které má Silverlight 2.0 integrované a tento výběr následně rozšíříme o další dva nástroje, které přináší Silverlight toolkit. Plus jeden šikovný nástroj nakonec.
Seriál: Praktické užití Silverlight 2.0 (12 dílů)
- Praktické užití Silverlight 2.0: Data Binding 15. 12. 2008
- Praktické užití Silverlight 2.0: DataGrid 22. 12. 2008
- Praktické užití Silverlight 2.0: UserControl 29. 12. 2008
- Co zajímavého přínáší Silverlight toolkit 5. 1. 2009
- Silverlight toolkit a vizualizace dat 12. 1. 2009
- Jak na komponenty AutoCompleteBox a TreeView ze Silverlight toolkitu 19. 1. 2009
- Nástroje pro tvorbu layoutu v Silverlightu 2.0 a Silverlight toolkitu 26. 1. 2009
- Design se styly a šablonami v Silverlightu 2.0 2. 2. 2009
- Základy 2D grafiky v Silverlightu 2.0 16. 2. 2009
- Dynamicky generované komponenty v Silverlightu 2.0 3. 3. 2009
- Úvod do streamování médií v Silverlightu 2.0 16. 3. 2009
- Práce s videem v Silverlightu 2.0 1. 6. 2009
Nálepky:
Úplně první věcí, kterou musíte udělat, při tvorbě uživatelského rozhraní, je vytvořit si kostru stránky – neboli layout. Toto pravidlo platí pro tvorbu uživatelského rozhraní ve všech jazycích popisujících GUI. Většinou platí, že změna layoutu vám zabere trojnásobek času, nežli jeho samotná tvorba. Proto je dobré si celý layout na začátku důkladně promyslet.
Silverlight 2.0 má integrované následující komponenty:
- Canvas – kontejner s možností definování pozic svých „potomků“
- StackPanel – kontejner umožňující řazení prvků horizontálně či vertikálně za sebou
- Grid – tabulka
- ScrollViewer – kontejner umožňující zobrazení posuvníků
S těmito nástroji si v drtivé většině vašich aplikací vystačíte. Proč si ale nezjednodušit život, když to jde pomocí komponent Silverlight toolkitu. Konkrétně těchto dvou:
- DockPanel – umožňuje orientování potomků různými směry
- WrapPanel – zajišťuje zalamování potomků do řádků či sloupců
Ještě bych rád na konec uvedl komponentu TabControl
. Zde by mohl někdo namítnout, že se nejedná o komponentu sloužící pro tvorbu layoutu. A měl by částečně i pravdu (jelikož se jedná o komponentu funkční). Nicméně z pohledu vývojáře či designera GUI je jednou z variant, se kterou musí počítat již při tvorbě layoutu.
Canvas
Canvas
je nejoblíbenějším a nejsvobodnějším nástrojem pro tvorbu layoutu. Čím to? Jeho hlavní funkcionalita spočívá v tom, že umožňuje potomkům (tedy všem komponentám, které jsou v Canvasu
obsaženy) definování pozice uvnitř Canvasu
. To z něj dělá jednoduchý, ale zároveň mocný nástroj pro tvorbu 2D grafiky.
Pojďme si ukázat velice jednoduchý příklad. Nakreslíme si smajlíka (který se moc nesměje). V kódu si všimněte třech hlavních prvků definujících prvek v Canvasu
– Top
, Left
, ZIndex
. První dva určují pozici a poslední úroveň (tzn. prvky s vyšším číslem budou překrývat prvky s nižším číslem).
<Canvas Width="200" Height="200">
<Ellipse Fill="Yellow"
Width="180"
Height="180"
Canvas.Left="10"
Canvas.Top="10"
Canvas.ZIndex="0"/>
<Ellipse Fill="Black"
Width="10"
Height="30"
Canvas.Top="60"
Canvas.Left="65"
Canvas.ZIndex="1"/>
<Ellipse Fill="Black"
Width="10"
Height="30"
Canvas.Top="60"
Canvas.Left="125"
Canvas.ZIndex="1"/>
<Line Stroke="Black"
X1="0"
X2="100"
Y1="0"
Y2="0"
Canvas.Left="50"
Canvas.Top="140"
Canvas.ZIndex="1"/>
</Canvas>
Výsledek:

StackPanel
Jedná se také o velice jednoduchý a velmi často používaný prvek (vždyť v jednoduchosti je krása). StackPanel využijeme hlavně tehdy, pokud budeme chtít prvky uspořádat horizontálně či vertikálně. Pojďme si StackPanel
ukázat v akci.
<StackPanel Orientation="Vertical" Width="100" Height="100" Background="Coral">
<Rectangle Fill="Black"
Width="20"
Height="20"
HorizontalAlignment="Center"/>
<Rectangle Fill="Black"
Width="20"
Height="20"
HorizontalAlignment="Left"/>
<Rectangle Fill="Black"
Width="20"
Height="20"
HorizontalAlignment="Right"/>
<Rectangle Fill="Black"
Width="20"
Height="20"
HorizontalAlignment="Center"/>
<Rectangle Fill="Black"
Width="20"
Height="20"
HorizontalAlignment="Right"/>
</StackPanel>
Výsledek:

Zde je vidět, jak se nám prvky skládají pod sebe a podle hodnoty atributu HorizontalAlignment
jsou zarovnány vlevo, vpravo nebo na střed.
Grid – tabulka
V minulých letech se stalo používání tabulky pro rozvržení stránky velice nepopulární. Za tento fakt mohlo z velké části HTML, kde opravdu rozvržení stránky pomocí tabulky nebývá šťastným řešením. Naopak u XAMLu je tento způsob rozvržení stránky jedním z nejčastějších.
Práce s tabulkou probíhá tak, že si nejdříve definujeme sloupce a řádky. Následně potomky adresně umísťujeme do vytvořených políček. Na následujícím příkladu si ukážeme, jak vytvořit formulář pro přihlášení.
<Grid ShowGridLines="True" Width="350" Height="250" Background="LightGray">
<!--definice sloupcu-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<!--definice radku-->
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<!--komponenty v tabulce-->
<TextBlock Text="Uživatelské jméno:"
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="2"/>
<TextBox Grid.Column="1"
Grid.Row="0"
Margin="2"/>
<TextBlock Text="Heslo:"
Grid.Column="0"
Grid.Row="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="2"/>
<TextBox Grid.Column="1"
Grid.Row="1"
Margin="2"/>
<Button Content="Přihlásit"
Grid.Column="1"
Grid.Row="2"
Margin="2"/>
</Grid>
Výsledek (linky tabulky jsou vidět jen tehdy, pokud máme nastaveno ShowGridLines
na True
– zde jsou jen pro ukázku):

Pokud budeme chtít, aby nějaké komponenty zasahovaly do více polí, použijeme k tomu Grid.RowSpan
a Grid.ColumnSpan
, kde definujeme, kolik řádků či sloupců komponenta zabere.
ScrollViewer
Kontejner ScrollViewer
používáme hlavně v případech, kdy víme, že dané pole bude mít více obsahu nežli mu dovolí jeho výška či šířka. ScrollViewer nám dovoluje si nastavit jejich zobrazování – zobrazeno neustále, automatické zobrazení nebo vypnuto.
<ScrollViewer Width="200" Height="200"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Disabled">
<!--text ci komponenty-->
</ScrollViewer>
Výsledek:

Komponenty Silverlight toolkitu
Ještě před tím než začneme používat komponenty Silverlight toolkitu, musíme přiřadit knihovnu obsahující komponenty do našeho projektu. Podrobný popis naleznete v předchozím článku.
DockPanel
Funkcionalita DockPanelu
spočívá v možnosti přiřazovat komponenty k různým stranám DockPanelu
– doprava, doleva, nahoru, dolu. Působí tedy jako mnohosměrný StackPanel
. Velkou výhodou ale je, že tyto komponenty spolu v DockPanelu
umí koexistovat a nepřekrývají se (jak vidíme na ukázce).
<Controls:DockPanel Height="200" Width="300" Background="LightGray" LastChildFill="True">
<Rectangle Fill="Blue" Controls:DockPanel.Dock="Top" Height="30"/>
<Rectangle Fill="Blue" Controls:DockPanel.Dock="Bottom" Height="30"/>
<Rectangle Fill="Black" Controls:DockPanel.Dock="Left" Width="30"/>
<Rectangle Fill="Red" Controls:DockPanel.Dock="Right" Width="30"/>
<Rectangle Fill="Green"/>
</Controls:DockPanel>
Vidíme zde 5 obdélníků. Každý je přiřazen k jedné straně a podle toho, jak vysoko jsou v kódu postaveni, taková je i jejich priorita vykreslení. LastChildFill
je nastaveno na True
, jelikož chceme, aby poslední obdélník vyplnil všechen zbývající prostor.

Pojďme si náš příklad trochu rozvinout a namísto horního a levého obdélníku si dát menu. Poslední využijeme například k vypsání obsahu.
<Controls:DockPanel Height="200" Width="300" Background="LightGray" LastChildFill="True">
<!--menu 1-->
<StackPanel Background="Blue"
Orientation="Horizontal"
Height="Auto"
Controls:DockPanel.Dock="Top">
<Button Content="#1" Width="55" Margin="2"/>
<Button Content="#2" Width="55" Margin="2"/>
<Button Content="#3" Width="55" Margin="2"/>
<Button Content="#4" Width="55" Margin="2"/>
<Button Content="#5" Width="55" Margin="2"/>
</StackPanel>
<!--zapati-->
<Rectangle Fill="Blue" Controls:DockPanel.Dock="Bottom" Height="30"/>
<!--menu 2-->
<StackPanel Background="Yellow"
Orientation="Vertical"
Height="Auto"
Controls:DockPanel.Dock="Left">
<Button Content="#01" Margin="2"/>
<Button Content="#02" Margin="2"/>
<Button Content="#03" Margin="2"/>
<Button Content="#04" Margin="2"/>
<Button Content="#05" Margin="2"/>
</StackPanel>
<!--pravy pruh-->
<Rectangle Fill="Red" Controls:DockPanel.Dock="Right" Width="30"/>
<!--obsah-->
<ScrollViewer VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Disabled">
<TextBlock Text="..."
TextWrapping="Wrap"/>
</ScrollViewer>
</Controls:DockPanel>
Výsledek:

WrapPanel
Tato komponenta také částečně vychází ze StackPanelu
. Pokud skládáte prvky ve WrapPanelu
za sebe a dojdete na konec panelu, následující komponenta bude již v dalším řádku či sloupci. Tato komponenta nalezne excelentní využití například při tvorbě fotogalerie či jakékoliv jiné galerie (ukázka jednoduché fotogalerie). Na příkladu si ukážeme, jak se prvky skládají do WrapPanelu
, pokud budeme hýbat s šířkou panelu. Nejprve si připravíme kód:
<Controls:WrapPanel Background="LightGray"
Orientation="Horizontal"
Height="250"
Width="120">
<Rectangle Fill="Black" Height="30" Width="60"/>
<Rectangle Fill="White" Height="10" Width="40"/>
<Rectangle Fill="Black" Height="20" Width="50"/>
<Rectangle Fill="White" Height="40" Width="40"/>
<Rectangle Fill="Black" Height="20" Width="30"/>
<Rectangle Fill="White" Height="10" Width="90"/>
<Rectangle Fill="Black" Height="40" Width="20"/>
<Rectangle Fill="White" Height="10" Width="90"/>
<Rectangle Fill="Black" Height="20" Width="120"/>
<Rectangle Fill="White" Height="40" Width="40"/>
<Rectangle Fill="Black" Height="20" Width="30"/>
<Rectangle Fill="White" Height="10" Width="90"/>
<Rectangle Fill="Black" Height="40" Width="20"/>
<Rectangle Fill="White" Height="10" Width="90"/>
<Rectangle Fill="Black" Height="20" Width="120"/>
</Controls:WrapPanel>
Výsledek:

Pokud změníme šířku WrapPanelu
na 200 px dostaneme následující výsledek, kde vidíme, že se obdélníky přeskládali do šířky WrapPanelu
.

A nakonec rozšíříme WrapPanel na 350 px.

TabControl
Tato komponenta slouží k separování určitých částí obsahu do různých tématických celků. Jedná se o komponentu, která nám může v mnoha případech pomoci zpřehlednit rozložení stránky. Namísto toho, abychom zobrazovali všechny informace vedle sebe nebo pod sebou, necháme uživatele, aby si zvolil sám, jakou informaci chce zobrazit. Tato komponenta je velice rozšířená především na desktopových platformách. Poslední dobou se ale čím dál tím častěji objevuje i na webu.
Proto, abychom mohly tuto komponentu použít, musíme zařadit do hlavičky jmenný prostor System.Windows.Controls, ve kterém TabControl
nalezneme. Pro jednoduchost můžeme také ve Visual Studiu přetáhnout TabControl
z Toolboxu. Visual Studio za nás následně vykoná přiřazení jmenného prostoru.
Pojďme si nyní vytvořit pár tabulek. Budeme chtít, aby každá obsahovala jiný prvek.
<basics:TabControl>
<basics:TabItem Header="Text">
<TextBox Text="Jmenuji se jan a mám rád dobré jídlo"
FontSize="38"
TextWrapping="Wrap"/>
</basics:TabItem>
<basics:TabItem Header="Kolečko">
<Ellipse Fill="Red"
Width="100"
Height="100"/>
</basics:TabItem>
<basics:TabItem Header="Obdélník">
<Rectangle Fill="Peru"
Height="100"
Width="200"/>
</basics:TabItem>
<basics:TabItem Header="Kalendář">
<basics:Calendar></basics:Calendar>
</basics:TabItem>
</basics:TabControl>
Všimněte si struktury TabControlu
, nejdříve definujeme celý TabControl
a následně do něj vkládáme jednotlivé položky. Výsledek bude vypadat nějak takto:

Příklad si můžete vyzkoušet online.
Online ukázka a zdrojové kódy
Všechny probrané příklady si můžete vyzkoušet online.
K dispozici máte také zdrojový kód všech ukázek: Demo tvorby layoutu v Silverlightu (ZIP 2977051 bytů).
Závěrem
Stejně tak jako tomu je v jiných jazycích, tak i u XAMLu je nutné při návrhu GUI mít určitou disciplínu. Jsou určité věci, kterým by jste se při tvorbě GUI měli vyhnout. Tou hlavní a zásadní je přílišné vnořování různých komponent (jinak byste mohli brzy volat: já se v tom nevyznám, já se v tom neorientuju). Pokud tomuto nešvaru podlehnete, tak je to téměř jistá cesta do XAML pekel. Dříve či později se vám stane, že se ve svém kódu nevyznáte.
Bohužel v tuto chvíli neexistuje žádná spásná „bible“, která by nám napovídala jak psát XAML kód (nebo jsem na ní v dosavadním pátrání nenarazil – pokud někdo z vás ano, prosím odkažte na ní v komentářích), abychom se za čas z něho nepomátli. Ale všeobecným pravidlem je: použít pro layout stránky vždy jen jeden dominantní prvek a ostatní používat jen tehdy, pokud jsme si jisti, že jsou přínosem (ne zkázou).
Co nás čeká příště?
V příštím díle se vrhneme po stopách stylování komponent a šablonách.
Tak jsem článek spíš zběžně prolétával a oko mi padlo na ScrollViewer. Přijde mi to hrozně nesmyslné :-), mnohem elegantnější mi přijde způsob, jaký se používá v HTML a CSS (tedy jednoduchý <div>, čili odstavec textu, a css vlastnost overflow).
Jako další nesmysl mi přijde to, že vlastnost *ScrollBarVisibility používá pro zobrazení "visible" a pro skrytí "disabled". Mnohem logičtější by bylo "visible/hidden" či "enabled/disabled". Ten, kdo to navrhoval, musel mít zrovna slabší chvilku:D
Aha, tak jsem si špatně s tou vlasností *ScrollBarVisiblity špatně přečetl:) Samozřejmě to význam má.
Do ScrollViewer můžete dát cokoliv, u čeho předpokládáte, že bude přesahovat rozměr vymezeného prostoru. Nejen ListBox.