Příklad obsahuje základy toho, co byste měli znát abyste uspěli u testu.
Test bude mít dvě části, písemný test a potom ústní rozpravu.
- Znalost základních pojmů View, ViewModel, Bindování, PropertyChanged, Command
- Znalost použití Bindování v jazyku XAML a C#
- Znalost použití eventu
PropertyChangeda rozhraníINotifyPropertyChanged - Vytváření instance ViewModelu v jazyce XAML nebo C#
- Znalost XAML jmenných prostorů, mapování XAML jmenných prostorů (
xmlns:x) a definice kódu na pozadí (x:Class) - Znalost použití třídy
Command - Znalost použití hierarchické navigace
- Znalost použití klíčových slov
asyncaawait
- View - typicky jedno okno aplikace, tedy to co vidí uživatel
- ViewModel - je třída obsahující data pro zobrazení, konkrétně property, které chceme zobrazovat ve View. Například MainViewModel. Mmodel jsou obecně data v paměti.
- Bindování - mechanismus pomocí kterého spolu komunikují View a View model a přitom na sebe nemají přímou referenci, což umožňuje nezávislý vývoj a testování.
- PropertyChanged - event v rozhraní INotifyPropertyChanged pomocí kterého ViewModel informuje control ve View, například TextBox, že došlo ke změně property ve ViewModelu a View ji má znovu načíst a zobrazit.
- Command - pomocí commandů může View volat metody ViewModelu a opět na sebe nemusí mít referenci. Commnand je potom třída implementující rozhraní ICommand. Ve ViewModelu potom vytváříme property typu Commmand a předáváme jí delegáta na metodu ve ViewModelu, kterou chceme zavolat. Ve View potom například Button na tuto property Command binduje.
Kód popisovaný v následujícím textu najdete v projektu Exam, který obsahuje kód společný pro všechny platformy.
Nejdůležitější soubory v projektu jsou:
-
MainPage.xaml - View obsahující hlavní stránku aplikace obsahující
LabelaButtonpro zvýšení hodnoty počítadla, reset hodnoty počítadla a pro editaci hodnoty počítadla, kdy naviguje na druhé View EditPage.xaml -
EditPage.xaml - View obsahující
Entrypro editaci hodnoty počítadla. -
CounterViewModel.cs - ViewModel, který má property
Number,CommandIncrease,CommandResetaCommandNavigateToEdit. Obě View v tomto příkladu sdílejí jednu instanci tohoto ViewModelu.
Dále si popíšeme základní principy použíté v tomto příkladu:
- Bindování
-
Nejprve vytvoříme v souboru App.xaml.cs instanci našeho ViewModelu a předáme ji v konstruktoru třídě
MainPage. Kvuli hierarchické navigaci navíc ještě použijeme tříduNavigationPage:MainPage mainPage = new MainPage(new CounterViewModel()); MainPage = new NavigationPage(mainPage);
Třída MainPage potom v konstruktoru nastaví svůj
BindingContextna referenci typuCounterViewModel:CounterViewModel _viewModelPocitadlo; public MainPage(CounterViewModel viewModelPocitadlo) { InitializeComponent(); _viewModelPocitadlo = viewModelPocitadlo; BindingContext = _viewModelPocitadlo; }
Poznámka: Instanci ViewModelu můžeme vytvářet různými způsoby, například přímo v jazyku XAML.
-
Pomocí markup extension
Bindingnabindujeme propertyTextelementuLabelna hodnotu propertyNumberobjektu přiřazeného propertěBidingContexttřídyMainPage, což je instance třídyCounterViewModelpřiřazená v předchozím kroku.<Label Text="{Binding Number}" />
Třída
CounterViewModelpotom obsahuje kromě jiného propertyNumber. Použití eventuPropertyChangevysvětlíme později:public class CounterViewModel : INotifyPropertyChanged { // dalsi kod public int Number { get { return _number; } set { _number = value; OnPropertyChanged();} } // dalsi kod }
-
Command
Nejprve ve ViewModelu vytvoříme property typu
Commanda poté vytvoříme její instanci. V konstruktoru jí potom předáme referenci na metodu, která se má zavolat když uživatel stiskne například tlačítko.Například v našem ViewModelu
CounterViewModelmáme propertyCommandIncreasetypuCommand:public Command CommandIncrease { get; set; }
V konstruktoru potom vytváříme instanci třídy
Commanda v konstruktoru jí předáváme referenci na metoduIncrease:CommandIncrease = new Command(Increase);
V metodě
Increasepotom zvyšujeme hodnotu počítadla reprezentovanou propertyNumber:private void Increase() { ++Number; }
Ve třídě
MainPagepotom bindujeme property Command třídy Button na propertyCommandIncreasetřídyCounterViewModel:<Button Text="Increase" Command="{Binding CommandIncrease}" />
Ve View EditPage potom bindujeme na property
Numberpomocí zápisuMode=TwoWayobousměrmě, tedy property můžemě i měnit:<Entry Text="{Binding Number, Mode=TwoWay}" Placeholder="number" SelectionLength="10" Keyboard="Numeric" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand" />
-
PropertyChanged
View aktivně nezjištujě zda se změnily hodnoty property ve ViewModelu a mají se zaktualizovat zobrazení. Aby nabidnované elementy ve View reagovali na změny musíme použít event
PropertyChangedz rozhraníInNotifyPropertyChanged.V našem příkladu implementuje rozhraní
InNotifyPropertyChangedpřímo třídaCounterViewModel. Díky použití atributu[CallerMemberName]nemusíme jako parametr předávat název property. Díky použití operátoru?.se metodaInvokenezavolá pokud by měl eventPropertyChangedhodnotunull.public class CounterViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName]string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } // dalsi kod }
Metodu
OnPropertyChangedpotom nejčastěji voláme se setteru property, například zde voláme tuto metodu v setteru propertyNumber:public int Number { get { return _number; } set { _number = value; OnPropertyChanged();} }
-
Navigace
V příkladu využíváme hierarchickou navigaci, proto jsme při vytváření instance třídy
MainPagepoužili i tříduNavigationPage.V příkladu potom máme v třídě
CounterViewModelpropertyCommandNavigateToEdit:public Command CommandNavigateToEdit { get; set; }
Pomocí tohoto Commandu potom voláme metodu
NavigateToEdit. V této metodě pomocí metodyPushAsyncnavigujeme na ViewEditPagea v konstrukotru předáváme pomocí klíčového slovathisreferenci naCounterViewModelve kterém se nacházíme. Obě View tedy budou sdílet stejný ViewModel.async private void NavigateToEdit() { EditPage editPage = new EditPage(this); INavigation navigation = Application.Current.MainPage.Navigation; await navigation.PushAsync(editPage); }
Poznámky:
- použití async a await není v tomto příkladě nutné. Mělo by význam jen, pokud bychom chtěli provést nejakou akci až potom co se navigace dokončí.
- Jednotlivá view nemusí vždy sdílet stejný ViewModel, záleží na typu aplikace. Často se v této souvisloti používá IoC konteiner, což jsem ale v tomto předmětu neprobírali.

