Lekce 5 - Code Behind v VB.NET WPF a dokončení kalkulačky
V minulém dílu, Návrh formuláře pro kalkulačku v VB.NET WPF, jsme nakódovali formulář pro jednoduchou kalkulačku.
Dnes do aplikace přidáme jednoduchou logiku a na konci si vysvětlíme jak WPF uvnitř funguje.
Code Behind
Prezentační část aplikace je napsaná v XAMLu. Ten nám však samozřejmě nestačí a proto má každé okno kromě XAML kódu ještě tzv. Code Behind (kód na pozadí), který obsahuje volání logiky aplikace. Do tohoto kódu se z designeru přesuneme pravým kliknutím myši a zvolením možnosti View Code. Alternativně můžeme používat klávesové zkratky CTRL + ALT + 0 (jedná se o nulu na alfanumerické klávesnici) pro přesun do Code Behind a Shift + F7 pro přesun do grafického návrháře.
Code Behind našeho formuláře vypadá asi takto (vynechal jsem jmenné prostory):
Class MainWindow End Class
Na pozadí tato třída dědí od třídy Window a má konstruktor, ve kterém se volá metoda InitializeComponent.
Pojmenování kontrolek
Když chceme s nějakou kontrolkou pracovat z Code Behind, musíme ji přiřadit jméno. V našem případě budeme při výpočtu potřebovat číst z dvou TextBoxů s čísly, ComboBoxu s operací, psát do TextBlocku s výsledkem a obsloužit událost kliknutí na tlačítko.
Přesuneme se zpět do XAMLu a těmto kontrolkám přiřadíme atribut Name s následující hodnotou pro jednotlivé kontrolky: cislo1TextBox, cislo2TextBox, operaceComboBox, vysledekTextBlock, vypocitejButton. Všimněte si, že jména jsme zvolili tak, aby končila názvem kontrolky. Při větších formulářích je to mnohem přehlednější. Určitě se vyvarujte názvům jako tlacitko1 a podobně.
Události
WPF jsou postavené na událostech. My budeme v kalkulačce reagovat na jedinou událost, kterou je kliknutí na tlačítko. V designeru na tlačítko poklepeme, budeme přepnuti do Code Behind, kde se nám vygeneruje následující metoda:
Private Sub vypocitejButton_Click(sender As Object, e As RoutedEventArgs) Handles vypocitejButton.Click End Sub
Metoda se spustí ve chvíli, kdy na tlačítko uživatel klikne. Využívá se jednoduše klíčového slova Handles, se kterým jsme se již setkali ve Windows Forms. Události můžeme přiřazovat a mazat také v oknu Properties. Stačí kontrolku označit a kliknout na ikonu blesku, čímž se přesuneme z vlastností do událostí. Tlačítko vedle nás poté přesune zpět na vlastnosti:

Do vygenerované metody vložme následující kód:
'Příprava proměnných Dim cislo1 As Double = cislo1TextBox.Text Dim cislo2 As Double = cislo2TextBox.Text Dim operace As String = operaceComboBox.Text Dim vysledek As Double = 0 'Výpočet Select Case operace Case "+" vysledek = cislo1 + cislo2 Case "-" vysledek = cislo1 - cislo2 Case "*" vysledek = cislo1 * cislo2 Case "/" If cislo2 = 0 Then MessageBox.Show("Nelze dělit nulou") Exit Sub End If vysledek = cislo1 / cislo2 End Select vysledekTextBlock.Text = vysledek
Na prvních řádcích si připravíme proměnné, do kterých uložíme potřebné hodnoty z kontrolek. K textu v TextBoxu i k vybrané textové položce ComboBoxu se dostaneme přes vlastnost Text. Vidíme zde, proč jsme kontrolky pojmenovávali. V aplikaci nijak neřešíme situaci, kdy uživatel zadá nesmyslný vstup a program tak spadne na výjimku při parsování této hodnoty. Jak se správně ošetřují chyby si ukážeme až v dalších dílech, můžete se sem poté vrátit a validaci dodat.
Výpočet výsledku by měl být jasný. Zajímavá je zde pouze kontrola, zda nedělíme nulou. Pokud ano, zobrazíme tzv. MessageBox, což je okno se zprávou pro uživatele, které jistě dobře znáte z jiných aplikací. Slouží nám k tomu stejnojmenná statická třída. MessageBox vypadá asi takto:

Na konci metody již jen přiřadíme do vlastnosti Text TextBlocku výsledek.
Můžete si aplikaci vyzkoušet.

WPF pod pokličkou
Než začneme zas pokročilejší látku, věnujme několik odstavců tomu, jak aplikace funguje pod pokličkou. Je to trochu taková teorie navíc, pokud jste nedočetli zdejší objektový seriál do konce, asi nebudete všemu rozumět, v praktickém vytváření aplikací vám to však nebude nijak bránit.
Parciální třída
Zaměřme se ještě jednou na třídu MainWindow (tedy na Code Behind). Třída je parciální. To znamená, že je definována ve více souborech. Ta druhá chybějící část je skrytá a můžeme do ni přejít tak, že v Solution Exploreru rozbalíte MainWindow tak, abyste viděli metodu InicializeComponents. Do metody přejdeme.

Dostali jsme se do poměrně ošklivé třídy, kterou nám Visual Studio samo vygenerovalo s novým oknem. Vidíme zde dvě metody: InitializeComponent() a Connect().
InitializeComponent() si načte XAML a zavolá na něj LoadComponent(). Všimněte si nad třídou atributů ze jmenného prostoru CodeDom. Zde jsou třídy pro generování VB kódu za běhu aplikace. Přesně to metoda dělá, parsuje XAML a vytváří podle něj instance kontrolek.
Metoda Connect() zprostředkovává ono magické napojení metod v CodeBehind.
Metoda zpřístupňuje jednotlivé kontrolky pod jejich názvy, to je
realizované tím ošklivým Select Case Do tohoto souboru nebudeme nikdy nijak zasahovat, je však
důležité, abychom chápali, jak WPF funguje.
Vytváření kontrolek za běhu aplikace
Jelikož kontrolky jsou obyčejné třídy, určitě vás napadlo, zda je můžeme na formulář přidávat tak, že vytvoříme jejich instance v Code Behind místo toho, abychom je psali do XAMLu. Ano, jde to. Teoreticky bychom XAML kód nemuseli vůbec používat. Prakticky bychom se však v návrhu formulářů vůbec nevyznali.
Ukažme si nějakou část našeho XAMLu, např. Grid. Ten vypadal takto:
<Grid Margin="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="50"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="50"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="30"/> </Grid.RowDefinitions> </Grid>
V Code Behind bychom stejného výsledku dosahli tímto zápisem:
Dim grid As New Grid() grid.Margin = DirectCast(TypeDescriptor.GetConverter(GetType(Thickness)).ConvertFromInvariantString("0"), Thickness) Dim columnDefinition As New ColumnDefinition() columnDefinition.Width = DirectCast(TypeDescriptor.GetConverter(GetType(GridLength)).ConvertFromInvariantString("*"), GridLength) grid.ColumnDefinitions.Add(columnDefinition) Dim columnDefinition2 As New ColumnDefinition() columnDefinition2.Width = DirectCast(TypeDescriptor.GetConverter(GetType(GridLength)).ConvertFromInvariantString("50"), GridLength) grid.ColumnDefinitions.Add(columnDefinition2) Dim columnDefinition3 As New ColumnDefinition() columnDefinition3.Width = DirectCast(TypeDescriptor.GetConverter(GetType(GridLength)).ConvertFromInvariantString("*"), GridLength) grid.ColumnDefinitions.Add(columnDefinition3) Dim columnDefinition4 As New ColumnDefinition() columnDefinition4.Width = DirectCast(TypeDescriptor.GetConverter(GetType(GridLength)).ConvertFromInvariantString("50"), GridLength) grid.ColumnDefinitions.Add(columnDefinition4) Dim columnDefinition5 As New ColumnDefinition() columnDefinition5.Width = DirectCast(TypeDescriptor.GetConverter(GetType(GridLength)).ConvertFromInvariantString("*"), GridLength) grid.ColumnDefinitions.Add(columnDefinition5) Dim rowDefinition As New RowDefinition() rowDefinition.Height = DirectCast(TypeDescriptor.GetConverter(GetType(GridLength)).ConvertFromInvariantString("*"), GridLength) grid.RowDefinitions.Add(rowDefinition) Dim rowDefinition2 As New RowDefinition() rowDefinition2.Height = DirectCast(TypeDescriptor.GetConverter(GetType(GridLength)).ConvertFromInvariantString("30"), GridLength) grid.RowDefinitions.Add(rowDefinition2)
Asi uznáte, že to není zrovna přehledné a to se jedná o malou část formuláře. Takže právě proto se používá XAML, kde je stromová struktura přehledná a jednoduchá.
Někdy však může být naopak užitečné vytvořit nějakou část aplikace nebo něco donastavit až v Code Behind místo v XAMLu. Účelem této části seriálu bylo, abyste věděli, že to jde.
Příště, Upomínač narozenin v VB .NET WPF - Návrh oken, začneme tvořit robustnější aplikaci, půjde o upomínač narozenin přátel. Zdrojové kódy kalkulačky jsou jako vždy ke stažení níže.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 118x (221.47 kB)
Aplikace je včetně zdrojových kódů v jazyce VB