Control templates
Posledním článkem ze série pro začátečníky dokončíme představení jednotlivých stránek WPF. Zároveň dokončíme aplikaci, kterou jsme začali postupně tvořit, a která na praktických příkladech demonstrovala použití jednotlivých technik pro tvorbu uživatelského rozhraní.
Control templates
Možná hned v úvodním článku jsem se zmiňoval o tom, že prvky ve WPF jsou označovány jako look-less, což znamená, že žádný prvek není pevně svázán s nějakým konkrétním vzhledem, pouze s nějakým výchozím, a tento vzhled mu může být změněn. Tudíž v případě potřeby mu může být vzhled kompletně pozměněn designerem nebo vývojářem.
Právě Control templates jsou tou správnou cestou, jak ke změně vizuálního vzhledu prvku dojít. Šablony jsou výkonnou a zajímavou variantou, jak ke změně vzhledu přistoupit a nabízejí mnoho způsobů použití – o Data templates jsme si již psali. Zároveň v nich můžeme uplatnit template binding, content a item presenters a další. Je toho skutečně mnoho a jednotlivé možnosti si zaslouží spíše samostatný článek, který detailněji popíše každou z možných technik.
Je zde asi jediný bod, který bych zmínil ihned. Tím je skutečnost, že šablony nahrazují pouze uživatelský vzhled rozhraní a nikoliv jeho funkčnost. Znamená to tedy, že případný designer aplikace může vytvořit zcela nový a působivý design pro ovládací prvek bez toho, aniž by ovlivlnil chování aplikace – napsaný kód. Takže vámi napsaný kód třeba v podobě obsluhy a přiřazení obsluhy události Click zůstane zachován a bude stále funkční, stejně jako dříve, než byla použita šablona.
To je myslím velice dobrá zpráva a otevírá to dveře dalším možnostem, které mohou vést třeba na prototypování uživatelského rozhraní a rozvržení jednotlivých ovládacích prvků a pouhou změnou šablony poté můžeme změnit jen vzhled daného prvku.
Dokončení aplikace – použití User control a Control template
V předchozím článku, kdy jsme si pověděli něco o User control jsem slíbil, že dokončíme aplikaci a využijeme tam ještě možnost umístění User control. Nyní tedy nastává ta správná chvíle.
Jak si jistě pamatujete, aplikace nyní nabízí zobrazení seznamu vín z vinotéky v poměrně působivé podobě. Co bychom však chtěli, dozvědět se přeci jen více o právě vybraném vínu. Právě s využitím a umístěním vytvořeného User control si zobrazíme detail, který nám sdělí další informace.
Vložme si tedy do aplikace přes menu novou položku, jejíž typ bude WPF User Control a pojmenujme ji WineDetailsView.xaml. Jak vidíte, tak se vytvoří opět dva soubory WineDetailsView.xaml a k němu přidružený WineDetailsView.xaml.cs. Nás bude zajímat jen xaml soubor, který má jako root tag uvedenu hodnotu <UserControl />. Jinak je vše stejné jako v případě deklarace <Window />. Do tohoto User controlu pak vložíme deklaraci pro UI, které nám má zobrazit požadovaný detail. Při deklaraci opět využijeme poznatků, které jsme již nabyli, jako je deklarace stylů, Data Binding, deklaraci rozvržení a v neposlední řadě i Control template.
User control si můžete prohlédnout v přiloženém souboru, který obsahuje celou hotovou aplikaci.
Abychom mohli tento námi vytvořený User control použít, potřebujeme jej zařadit do vizuálního stromu dokumentu a zároveň pro něj zaregistrovat xmlns. To provedeme takto, v elementu <Window /> uvedeme deklaraci namespace
xmlns:coho="clr-namespace:CohoWpfApplication"
a náš user control umístíme za element <ListBox />
<coho:WineDetailsView x:Name='WineDetail' Grid.RowSpan='2' Visibility='Collapsed' />
jak vidíte, ve výchozím stavu bude tento User control sbalený. Rozbalíme jej totiž až v okamžiku, kdy vybereme nějaké víno ze seznamu.
Abychom si demonstrovali možnosti, jak můžeme snadno využít mixovaní mezi xaml deklarací a c# zápisem, provedeme si přiřazení handleru pro změnu výběru v listboxu přímo v c# a zapíšeme si i obsluhu události.
public Window1() { InitializeComponent(); WineListBox.SelectionChanged += new SelectionChangedEventHandler(WineListBox_SelectionChanged); }
a obsluha události
void WineListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { Wines wine = WineListBox.SelectedItem as Wines; if (wine != null) { WineDetail.DataContext = wine; WineDetail.Visibility = Visibility.Visible; } }
zde si všimneme, že nejdříve otestujeme, zda je vybrána nějaká položka v ListBoxu a pokud ano, tak celý objekt předáme do DataContext vlastnosti námi vytvořeného User controlu. Na dalším řádku pak zviditelníme celý User control.
DataContext vlastnost
Možná by bylo vhodné si v tuto chvíli říci něco o vlastnosti DataContext. Ta slouží pro uchování reference na data, která jsou platná v dané oblasti. Téměř každý prvek (ty poděděné od FrameworkElement) obsahuje tuto vlastnost a v případě, že je mu přiřazena, tak se ruší platnost DataContextu nadřazeného. Z tohoto contextu je poté možné přebírat data pro binding.
DataContext vlastnosti budeme hojně využívat v dalších článcích, které se budou věnovat vývoji za pomoci návrhových vzorů používaných při tvorbě WPF/Silverlight aplikací.
Ne neposledním úkolem je obsloužit obsluhu události kliknutí na tlačítko, které je umístěno v našem User controlu tak, aby došlo opět k zneviditelní tohoto prvku a uživatel tak dostal možnost vybrat jiný druh vína. Obsluha události je velice jednoduchá a čítá celkem jeden řádek
void CloseBtn_Click(object sender, RoutedEventArgs e) { Visibility = Visibility.Collapsed; }
Použití Control templates
Ten kdo si otevřel přiloženou aplikaci již vidí vše tak jak má a jaký je cílový stav aplikace. Abychom se však dostali do stavu a ukázali si, jak by vypadala aplikace, kdybychom neznali nic o používání Control templates můžeme provést následující krok. Najděte si v našem User controlu WineDetailsView následující řádek
<Button Click="CloseBtn_Click" Content="Close" Style='{StaticResource CloseButton}' />
a odstraňte deklaraci pro styl – s názvem CloseButton. Rázem uvidíte změnu tlačítka na jeho výchozí vzhled, který tak nějak nepasuje do námi vytvořeného a deklarovaného stylu aplikace. Pokud tam tedy zpátky vrátite přiřazení stylu a podíváme se na deklaraci stylu uvidíme, jak se nám tlačítko může snadno změnit.
Daný styl vypadá následovně
<Style x:Key="CloseButton" TargetType="Button"> <Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="Width" Value="50"/> <Setter Property="Height" Value="25"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Border x:Name="brd1" Width="22" Height="22" CornerRadius="15"> <TextBlock x:Name="txt1" Foreground="#222" TextAlignment="center" Text="r" FontSize="11" VerticalAlignment="center" FontFamily="Webdings"/> <Border.Background> <RadialGradientBrush GradientOrigin=".3, .3"> <GradientStop Color="#FFF" Offset=".15"/> <GradientStop Color="#777" Offset="1"/> </RadialGradientBrush> </Border.Background> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
asi nejzajímavější na deklaraci tohoto stylu je, že jsem definoval vlastnost Template a jako hodnotu ji přiřadit deklaraci ControlTemplate. Ten pak v našem případě obsahuje rámeček, který díky zaoblení rohů vytvoří kolečko, dále TextBlock, který díky použitému fontu vytvoří křížek a dále deklaraci pozadí, které na tlačítku vytvoří požadovaný přechod.
Jak sami vidíte, nezasáhli jsme jakkoliv do funkčnosti daného tlačítka, to zůstává stále klikací a vyvolává se tak obsluha události, co se však radikálně změnilo je vzhled tlačítka.
Závěrem
Naše společné odhalování základů WPF pomalu končí, já doufám, že se mi povedlo vám WPF představit a alespoň maličko poodhalit jeho zákoutí, jeho krásu a smyslnost, kterou nabízí jak vývojářům tak i designérům uživatelského rozhraní.
V případě, že máte jakékoliv připomínky nebo dotazy, zanechejte svoji otázku nebo dotaz v komentářích a já se pokusím na ně odpovědět, ať už reakcí na komentář nebo samostatným článkem.
Další články se budou již věnovat pokročilejším technikám práce nejen s WPF, ale rád bych, aby to nebylo jen pro pokročilé vývojáře, ale i pro ty začínající, které by měly zdejší články nasměrovat na správnou cestu, jak snadno vytvářet uživatelsky přívětivé a zároveň snadno spravovatelné a vyvíjené aplikace.
Přiložená aplikace
Zároveň s tímto posledním článkem přikládám hotovou aplikaci, která obsahuje všechny probraná témata. Jedinou změnou, kterou bude třeba udělat je nastavení korektního connection stringu v souboru app.config na přiloženou databázi.
Komentáře