Dnes to bude o designu – popíšeme si dostupné kontejnery pro ovládací prvky v Silverlightu a vytvoříme grafické prostředí Digg klienta.
Informace obsažené v tomto dílu můžete využít i při návrhu grafiky v Blendu, ale jak už jsem řekl v úvodním dílu, ten my používat nebudeme – všechen XAML si napíšeme ručně. Dnes začneme otevřením projektu z minulého dílu.
Layout controls
V Silverlightu i ve WPF můžeme nastavovat polohu jednotlivých ovládacích prvků pomocí explicitně zadaných souřadnic (nechť je tlačítko vždy na souřadnicích [130;20]), anebo dynamicky a prvky se pak přeskupují podle velikosti okna (nechť je TextBox vždy uprostřed okna).
Existují tzv. „layout controls“, tedy vlastně kontejnery, které podle nějakých pravidel seskupují další ovládací prvky uvnitř sebe. Současná verze Silverlightu obsahuje jen tři základní kontejnery – Canvas, StackPanel a Grid (WPF je v tomto ohledu bohatší, snad se dočkáme třeba WrapPanelu i v Silverlightu). Na všechny tři silverlightovské kontejnery se nyní podíváme podrobněji.
Canvas Panel
Canvas je ten nejjednodušší ze všech, podporuje pozicování prvků do něj umístěných pomocí explicitně zadaných souřadnic.
Pozicování provádíme pomocí vlastností zvaných „attached properties“ (něco ve smyslu „přichycovacích vlastností“). Attached properties nám umožní specifikovat pozici prvku relativně k okrajím mateřského Canvasu, tyto vlastnosti jsou tedy vlastně enumerací s hodnotami Left, Top, Right a Bottom.
Ukážeme si to na příkladu. V XAMLu si napíšeme Canvas a do něj umístíme dvě tlačítka umístěná 50 pixelů zleva a 50 a 150 pixelů shora (v příkladu jsou attached properties právě Canvas.Left a Canvas.Top).
<UserControl x:Class="DiggKlient.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Canvas Background="#FF5C7590">
<Button Content="Tlačítko 1" Width="100" Height="50" Canvas.Left="50" Canvas.Top="50" />
<Button Content="Tlačítko 2" Width="100" Height="50" Canvas.Left="50" Canvas.Top="150" />
</Canvas>
</UserControl>
Pokud aplikaci spustíme (pomocí Ctrl + F5), dostaneme tento výsledek:
Canvas je užitečný pro vkládání prvků, které zůstanou na nějaké fixní pozici. Naopak je velmi špatný nápad snažit se ho použít na prvky, které se nějak pohybují, museli bychom psát kód na změnu souřadnic. Mnohem lepším řešením je použít kontejnery, které jsou za tímto účel už udělané, jako třeba StackPanel a Grid.
StackPanel
Kontejner StackPanel slouží k řazení prvků za sebou, vodorovně nebo svisle. Typickým scénářem využití je situace, kdy potřebujeme seřadit například několik tlačítek za sebou. Zařadit za sebe vertikálně tři tlačítka s 10px mezerou můžeme následovně:
<UserControl x:Class="DiggKlient.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel Background="#FF5C7590">
<Button Content="Tlačítko 1" Width="100" Height="50" Margin="10" />
<Button Content="Tlačítko 2" Width="100" Height="50" Margin="10" />
</StackPanel>
</UserControl>
Po spuštění se dočkáme očekávaného výsledku:
Nastavit StackPanel na horizontální můžeme pomocí vlastnosti Orientation s hodnotou „Horizontal“:
<StackPanel Orientation="Horizontal" Background="#FF5C7590">
<Button Content="Tlačítko 1" Width="100" Height="50" Margin="10" />
<Button Content="Tlačítko 2" Width="100" Height="50" Margin="10" />
<Button Content="Tlačítko 3" Width="100" Height="50" Margin="10" />
</StackPanel>
Grid Panel
Grid Panel je nejflexibilnější z kontejnerů dostupných v Silverlightu, umožňuje vkládat prvky do řádků a sloupců nadefinovaných v Gridu. Koncept je podobný jako element table v HTML.
Funguje to tak, že si pomocí vlastností
Například takto vytvoříme Grid o třech řádkách a třech sloupcích a vložíme do něj čtyři tlačítka:
<UserControl x:Class="DiggKlient.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid Background="#FF5C7590">
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="60" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110" />
<ColumnDefinition Width="110" />
<ColumnDefinition Width="110" />
</Grid.ColumnDefinitions>
<Button Content="Tlačítko 1" Width="100" Height="50" Grid.Column="1" Grid.Row="0" />
<Button Content="Tlačítko 2" Width="100" Height="50" Grid.Column="2" Grid.Row="1" />
<Button Content="Tlačítko 3" Width="100" Height="50" Grid.Column="0" Grid.Row="1" />
<Button Content="Tlačítko 4" Width="100" Height="50" Grid.Column="1" Grid.Row="2" />
</Grid>
</UserControl>
Kromě absolutního nastavení velikosti (Height=“60“) podporuje Grid i nastavování buněk automaticky, podle obsahu do nich vloženého (Height=“Auto“). Časem zjistíte, že Grid je nejflexibilnější a nejmocnější kontejner ze všech a budete ho používat nejčastěji. Několik jeho dalších schopností si ukážeme během seriálu, ale umí toho mnohem více.
Používání kontejnerů k návrhu designu
Naším cílem je vytvořit Digg klienta podobného tomu z minulého dílu, takže začneme. Jako první si nadefinujeme Grid se dvěma řádky. První řádek (Row) bude 40 px vysoký a druhý řádek vyplní zbytek Gridu (pomocí Height=“*“):
<UserControl x:Class="DiggKlient.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid Background="#FF5C7590" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
</UserControl>
V Gridu jsme nastavili vlastnost ShowGridLines na True, ta nám zobrazí hranice řádků a sloupců tabulky.
Teď vložíme druhý Grid jako dceřiný prvek do prvního řádku původního Gridu a rozdělíme ho na tři sloupce – jeden pro hlavičku aplikace, jeden pro vyhledávací políčko a třetí pro tlačítko Hledat.
<UserControl x:Class="DiggKlient.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid Background="#FF5C7590" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="7" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
</Grid>
</Grid>
</UserControl>
Místa pro jednotlivé prvky už máme připravená, takže teď jdeme na nějaký obsah. Jako hlavičku použijeme prvek Border (se zaoblenými rohy pomocí vlastnosti CornerRadius=“10“) a dovnitř napíšeme text. Do druhého sloupce vložíme TextBox pro vyhledávání a tlačítko (Button) do třetího sloupce. V druhém řádku (tedy ve zbytku aplikace) pak budeme zobrazovat výsledky hledání. Nezapomeňte si vhodně pojmenovat tlačítko (SearchBtn) a TextBox (TopicTB), protože se na ně budeme v dalších dílech v C# kódu odkazovat.
<UserControl x:Class="DiggKlient.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid Background="#FF5C7590" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="7" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" CornerRadius="10" Background="#FFDEDEDE" Margin="0,0,5,0">
<TextBlock Text="Digg klient" Foreground="#FF14517B" Margin="10,3,0,0" />
</Border>
<TextBox x:Name="TopicTB" Grid.Column="1" FontSize="14" />
<Button x:Name="SearchBtn" Grid.Column="2" Content="Hledat" />
</Grid>
<TextBlock Grid.Row="1" Margin="10" Foreground="White">
Zde budeme vypisovat výsledky
</TextBlock>
</Grid>
</UserControl>
Dynamické nastavení velikosti okna aplikace
Pokud si prohlédnete náš dosavadní XAML kód, zjistíte, že hlavní „okno“ naší aplikace má nastavenou pevnou šířku a výšku (momentálně 400 px, resp. 300 px). Když aplikace spustíme a zvětšíme okno prohlížeče, dostaneme nepříliš estetický výsledek:
Někdy se takové chování může hodit (zejména pokud vkládáme Silverlight aplikace do jiné stránky), ale toto není jeden z případů. Řešení je ale jednoduché, stačí jen odebrat atributy Width and Height, kód prvku UserControl pak bude vypadat nějak takto:
<UserControl x:Class="DiggKlient.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
Při změně velikosti okna prohlížeče se roztáhne Border a TextBlock v něm, protože ostatní sloupce Gridu mají fixní délku, zatímco sloupec s Borderem má šířku nastavenou na „*“.
V dalším dílu uděláme vyhledávání na Digg.com a výsledky naplníme DataGrid, příště tedy napíšeme i trochu C# kódu.