The Model-View-ViewModel Pattern

Poznámka:

Tato elektronická kniha byla publikována na jaře roku 2017 a od té doby nebyla aktualizována. Existuje mnoho v knize, která zůstává cenná, ale některé materiály jsou zastaralé.

Vývojářské Xamarin.Forms prostředí obvykle zahrnuje vytvoření uživatelského rozhraní v jazyce XAML a následné přidání kódu, který funguje v uživatelském rozhraní. Když se aplikace mění a zvětšují se jejich velikost a rozsah, můžou nastat složité problémy s údržbou. Mezi tyto problémy patří úzká párování mezi ovládacími prvky uživatelského rozhraní a obchodní logikou, což zvyšuje náklady na úpravy uživatelského rozhraní a potíže s testováním jednotek takového kódu.

Model-View-ViewModel (MVVM) pomáhá vyčistit obchodní a prezentační logiku aplikace od uživatelského rozhraní. Udržování čistého oddělení mezi logikou aplikace a uživatelským rozhraním pomáhá řešit řadu problémů s vývojem a může usnadnit testování, údržbu a vývoj aplikace. Může také výrazně zlepšit příležitosti opětovného použití kódu a umožňuje vývojářům a návrhářům uživatelského rozhraní snadněji spolupracovat při vývoji příslušných částí aplikace.

Model MVVM

Model MVVM obsahuje tři základní komponenty: model, zobrazení a model zobrazení. Každý z nich slouží k odlišnému účelu. Obrázek 2–1 znázorňuje vztahy mezi třemi komponentami.

The MVVM pattern

Obrázek 2–1: Model MVVM

Kromě porozumění zodpovědnostem jednotlivých komponent je také důležité pochopit, jak spolu vzájemně spolupracují. Na vysoké úrovni zobrazení "zná" model zobrazení a model zobrazení "ví o" modelu, ale model zobrazení nezná model zobrazení a model zobrazení toto zobrazení nezná. Model zobrazení proto izoluje zobrazení od modelu a umožňuje, aby se model vyvinul nezávisle na zobrazení.

Výhody použití modelu MVVM jsou následující:

  • Pokud existuje existující implementace modelu, která zapouzdřuje existující obchodní logiku, může být obtížné nebo rizikové ji změnit. V tomto scénáři model zobrazení funguje jako adaptér pro třídy modelu a umožňuje vyhnout se provádění významných změn kódu modelu.
  • Vývojáři můžou vytvářet testy jednotek pro model zobrazení a model bez použití zobrazení. Testy jednotek pro model zobrazení můžou provádět přesně stejné funkce jako zobrazení.
  • Uživatelské rozhraní aplikace je možné přepracovat bez zásahu do kódu za předpokladu, že se zobrazení implementuje zcela v XAML. Proto by nová verze zobrazení měla fungovat s existujícím modelem zobrazení.
  • Návrháři a vývojáři můžou během procesu vývoje pracovat nezávisle a souběžně na svých komponentách. Návrháři se můžou zaměřit na zobrazení, zatímco vývojáři můžou pracovat na modelu zobrazení a komponentách modelu.

Klíčem k efektivnímu používání virtuálního počítače MVVM je pochopení, jak začlenit kód aplikace do správných tříd a jak třídy interagují. Následující části diskutují o zodpovědnostech jednotlivých tříd v modelu MVVM.

Zobrazení

Zobrazení zodpovídá za definování struktury, rozložení a vzhledu toho, co uživatel vidí na obrazovce. V ideálním případě je každé zobrazení definováno v XAML s omezeným kódem, který neobsahuje obchodní logiku. V některých případech ale kód na pozadí může obsahovat logiku uživatelského rozhraní, která implementuje vizuální chování, které je obtížné vyjádřit v JAZYCE XAML, například animace.

Xamarin.Forms V aplikaci je zobrazení obvykle odvozenou nebo ContentViewodvozenou Pagetřídou. Zobrazení ale mohou být reprezentována také šablonou dat, která určuje prvky uživatelského rozhraní, které se mají použít k vizuálnímu znázornění objektu při zobrazení. Šablona dat jako zobrazení neobsahuje žádný kód a je navržená tak, aby se svážela s konkrétním typem modelu zobrazení.

Tip

Vyhněte se povolení a zakázání prvků uživatelského rozhraní v kódu. Ujistěte se, že modely zobrazení odpovídají za definování změn logického stavu, které ovlivňují některé aspekty zobrazení, například jestli je příkaz k dispozici, nebo indikaci, že operace čeká na vyřízení. Proto povolte a zakažte prvky uživatelského rozhraní vazbou pro zobrazení vlastností modelu, a ne jejich povolení a zakázání v kódu.

Existuje několik možností spuštění kódu v modelu zobrazení v reakci na interakce v zobrazení, například kliknutí na tlačítko nebo výběr položky. Pokud ovládací prvek podporuje příkazy, vlastnost ovládacího prvku Command může být vázána na ICommand vlastnost v modelu zobrazení. Po vyvolání příkazu ovládacího prvku se spustí kód v modelu zobrazení. Kromě příkazů je možné chování připojit k objektu v zobrazení a naslouchat buď vyvolání příkazu, nebo událost, která se má vyvolat. V reakci na toto chování pak může vyvolat ICommand model zobrazení nebo metodu modelu zobrazení.

ViewModel

Model zobrazení implementuje vlastnosti a příkazy, ke kterým může zobrazení vytvořit vazbu dat, a upozorní zobrazení změn stavu prostřednictvím událostí oznámení o změnách. Vlastnosti a příkazy, které model zobrazení poskytuje, definují funkce, které má uživatelské rozhraní nabídnout, ale zobrazení určuje, jak se má tato funkce zobrazit.

Tip

Udržujte uživatelské rozhraní responzivní pomocí asynchronních operací. Mobilní aplikace by měly vést k odblokování vlákna uživatelského rozhraní, aby se zlepšilo vnímání výkonu uživatele. Proto v modelu zobrazení použijte asynchronní metody pro vstupně-výstupní operace a vyvolání událostí, které asynchronně upozorňují zobrazení změn vlastností.

Model zobrazení je také zodpovědný za koordinaci interakcí zobrazení se všemi třídami modelu, které jsou požadovány. Mezi modelem zobrazení a třídami modelu modelu je obvykle relace 1:N. Model zobrazení se může rozhodnout vystavit třídy modelu přímo do zobrazení, aby ovládací prvky v zobrazení mohly data svázat přímo s nimi. V tomto případě budou třídy modelu muset být navrženy tak, aby podporovaly datové vazby a změny událostí oznámení.

Každý model zobrazení poskytuje data z modelu ve formuláři, který může zobrazení snadno využívat. K tomu model zobrazení někdy provádí převod dat. Umístění tohoto převodu dat do modelu zobrazení je vhodné, protože poskytuje vlastnosti, se kterými může zobrazení vytvořit vazbu. Model zobrazení může například zkombinovat hodnoty dvou vlastností, aby bylo zobrazení jednodušší.

Tip

Centralizace převodů dat ve vrstvě převodu Převaděče je také možné použít jako samostatnou vrstvu převodu dat, která se nachází mezi modelem zobrazení a zobrazením. To může být nezbytné například v případě, že data vyžadují speciální formátování, které model zobrazení neposkytuje.

Aby se model zobrazení mohl v zobrazení účastnit obousměrné datové vazby, musí PropertyChanged její vlastnosti vyvolat událost. Zobrazit modely splňují tento požadavek implementací INotifyPropertyChanged rozhraní a vyvoláním PropertyChanged události při změně vlastnosti.

Pro kolekce je k dispozici popisný ObservableCollection<T> pro zobrazení. Tato kolekce implementuje oznámení o změněných kolekcí, což vývojářům brání v implementaci INotifyCollectionChanged rozhraní v kolekcích.

Model

Třídy modelu jsou ne vizuálové třídy, které zapouzdřují data aplikace. Model si proto můžete představit jako reprezentaci doménového modelu aplikace, který obvykle zahrnuje datový model spolu s obchodní a ověřovací logikou. Mezi příklady objektů modelu patří objekty pro přenos dat (DTO), objekty CLR (Plain Old CLR Objects) a vygenerované entity a objekty proxy.

Třídy modelů se obvykle používají ve spojení se službami nebo úložišti, které zapouzdřují přístup k datům a ukládání do mezipaměti.

Připojení zobrazení modelů do zobrazení

Modely zobrazení lze připojit k zobrazením pomocí funkcí datové vazby .Xamarin.Forms Existuje mnoho přístupů, které lze použít k vytvoření zobrazení a zobrazení modelů a jejich přidružení za běhu. Tyto přístupy spadají do dvoukategoriích Volba mezi zobrazením prvního složení a prvním složením modelu zobrazení je problém s předvolbou a složitostí. Všechny přístupy však sdílejí stejný cíl, což je pro zobrazení mít model zobrazení přiřazený k jeho BindingContext vlastnost.

S prvním složením aplikace se koncepčně skládá ze zobrazení, která se připojují k modelům zobrazení, na které závisí. Hlavní výhodou tohoto přístupu je, že usnadňuje vytváření volně propojených aplikací testovatelných jednotek, protože modely zobrazení nemají žádnou závislost na samotných zobrazeních. Je také snadné pochopit strukturu aplikace pomocí vizuální struktury, a nemusíte sledovat provádění kódu, abyste pochopili, jak se třídy vytvářejí a přidruží. Kromě toho je první konstrukce v souladu s navigačním Xamarin.Forms systémem, který je zodpovědný za vytváření stránek při navigaci, což vytváří model zobrazení jako první složité a nesprávně zarovnané s platformou.

Při prvním složení modelu zobrazení se aplikace koncepčně skládá z modelů zobrazení, přičemž služba zodpovídá za vyhledání zobrazení modelu zobrazení. Zobrazení prvního složení modelu je pro některé vývojáře přirozenější, protože vytváření zobrazení může být abstrahováno, což jim umožňuje zaměřit se na logickou strukturu aplikace bez uživatelského rozhraní. Kromě toho umožňuje vytvářet modely zobrazení jinými modely zobrazení. Tento přístup je ale často složitý a může být obtížné pochopit, jak se vytvářejí a přidružují různé části aplikace.

Tip

Udržujte modely zobrazení a zobrazení nezávislé. Vazba zobrazení na vlastnost ve zdroji dat by měla být hlavní závislost zobrazení na příslušném modelu zobrazení. Konkrétně neodkazujte na typy zobrazení, jako Button jsou například a ListView, z modelů zobrazení. Podle zde uvedených principů lze modely zobrazení testovat izolovaně, a tím snížit pravděpodobnost vad softwaru omezením rozsahu.

V následujících částech najdete hlavní přístupy k připojování modelů zobrazení k zobrazení.

Vytvoření modelu zobrazení deklarativním způsobem

Nejjednodušším přístupem je, aby zobrazení deklarativně vytvořilo instanci odpovídajícího modelu zobrazení v XAML. Při vytváření zobrazení se vytvoří také odpovídající objekt modelu zobrazení. Tento přístup je ukázaný v následujícím příkladu kódu:

<ContentPage ... xmlns:local="clr-namespace:eShop">  
    <ContentPage.BindingContext>  
        <local:LoginViewModel />  
    </ContentPage.BindingContext>  
    ...  
</ContentPage>

ContentPage Při vytvoření je instance objektu LoginViewModel automaticky vytvořena a nastavena jako zobrazení BindingContext.

Tato deklarativní konstrukce a přiřazení modelu zobrazení podle zobrazení má výhodu, že je jednoduchá, ale má nevýhodu, že v modelu zobrazení vyžaduje výchozí konstruktor (bez parametrů).

Programové vytvoření modelu zobrazení

Zobrazení může mít kód v souboru kódu, který vede k modelu zobrazení, který je přiřazen k jeho BindingContext vlastnosti. To se často provádí v konstruktoru zobrazení, jak je znázorněno v následujícím příkladu kódu:

public LoginView()  
{  
    InitializeComponent();  
    BindingContext = new LoginViewModel(navigationService);  
}

Programová konstrukce a přiřazení modelu zobrazení v kódu zobrazení má výhodu, že je jednoduchá. Hlavní nevýhodou tohoto přístupu je ale to, že zobrazení musí poskytnout model zobrazení se všemi požadovanými závislostmi. Použití kontejneru injektáže závislostí může pomoct udržovat volné spojení mezi zobrazením a modelem zobrazení. Další informace naleznete v tématu Injektáž závislostí.

Vytvoření zobrazení definovaného jako šablona dat

Zobrazení lze definovat jako šablonu dat a přidružit k typu modelu zobrazení. Šablony dat je možné definovat jako prostředky nebo je lze definovat přímo v ovládacím prvku, který zobrazí model zobrazení. Obsah ovládacího prvku je instance modelu zobrazení a šablona dat se používá k vizuálnímu znázornění. Tato technika je příkladem situace, ve které se model zobrazení vytvoří jako první, následovaný vytvořením zobrazení.

Automatické vytvoření modelu zobrazení pomocí lokátoru modelu zobrazení

Lokátor modelu zobrazení je vlastní třída, která spravuje vytváření instancí modelů zobrazení a jejich přidružení k zobrazením. V mobilní aplikaci ViewModelLocator eShopOnContainers má třída připojenou vlastnost , AutoWireViewModelkterá se používá k přidružení modelů zobrazení k zobrazení. V xaml zobrazení je tato připojená vlastnost nastavena na hodnotu true, která označuje, že model zobrazení by měl být automaticky připojen k zobrazení, jak je znázorněno v následujícím příkladu kódu:

viewModelBase:ViewModelLocator.AutoWireViewModel="true"

Vlastnost AutoWireViewModel je bindable vlastnost, která je inicializována na false, a když její hodnota změní obslužnou rutinu OnAutoWireViewModelChanged události je volána. Tato metoda vyřeší model zobrazení pro zobrazení. Následující příklad kódu ukazuje, jak toho dosáhnout:

private static void OnAutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue)  
{  
    var view = bindable as Element;  
    if (view == null)  
    {  
        return;  
    }  

    var viewType = view.GetType();  
    var viewName = viewType.FullName.Replace(".Views.", ".ViewModels.");  
    var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;  
    var viewModelName = string.Format(  
        CultureInfo.InvariantCulture, "{0}Model, {1}", viewName, viewAssemblyName);  

    var viewModelType = Type.GetType(viewModelName);  
    if (viewModelType == null)  
    {  
        return;  
    }  
    var viewModel = _container.Resolve(viewModelType);  
    view.BindingContext = viewModel;  
}

Metoda OnAutoWireViewModelChanged se pokusí vyřešit model zobrazení pomocí konvenčního přístupu. Tato konvence předpokládá, že:

  • Modely zobrazení jsou ve stejném sestavení jako typy zobrazení.
  • Zobrazení jsou v . Zobrazení podřízeného oboru názvů
  • Zobrazit modely jsou v . Podřízený obor názvů ViewModels
  • Zobrazit názvy modelů odpovídají názvům zobrazení a končí na ViewModel.

OnAutoWireViewModelChanged Nakonec metoda nastaví BindingContext typ zobrazení na vyřešený typ modelu zobrazení. Další informace o řešení typu modelu zobrazení najdete v tématu Řešení.

Tento přístup má výhodu, že aplikace má jednu třídu, která odpovídá za vytvoření instance modelů zobrazení a jejich připojení k zobrazením.

Tip

Pro usnadnění nahrazení použijte lokátor modelu zobrazení. Lokátor modelu zobrazení lze také použít jako bod nahrazení alternativních implementací závislostí, jako je testování jednotek nebo data doby návrhu.

Aktualizace zobrazení v reakci na změny v podkladovém modelu zobrazení nebo modelu

Všechny třídy modelu zobrazení a modelu, které jsou přístupné pro zobrazení, by měly implementovat INotifyPropertyChanged rozhraní. Implementace tohoto rozhraní v modelu zobrazení nebo třídě modelu umožňuje třídě poskytovat oznámení o změnách pro všechny ovládací prvky vázané na data v zobrazení, když se změní hodnota podkladové vlastnosti.

Aplikace by měly být navrženy pro správné použití oznámení o změně vlastnosti splněním následujících požadavků:

  • Vždy vyvolání PropertyChanged události, pokud se změní hodnota veřejné vlastnosti. Nepředpokládáme, že vyvolání PropertyChanged události je možné ignorovat z důvodu znalostí o tom, jak dochází k vazbě XAML.
  • Vždy vyvolání PropertyChanged události pro všechny počítané vlastnosti, jejichž hodnoty jsou používány jinými vlastnostmi v modelu zobrazení nebo modelu.
  • Vždy vyvolání PropertyChanged události na konci metody, která provede změnu vlastnosti, nebo pokud je objekt známý jako v bezpečném stavu. Vyvolání události přeruší operaci tím, že vyvolá obslužné rutiny události synchronně. Pokud k tomu dojde uprostřed operace, může objekt vystavit funkcím zpětného volání, pokud je v nebezpečném, částečně aktualizovaném stavu. Kromě toho je možné kaskádové změny aktivovat událostmi PropertyChanged . Kaskádové změny obecně vyžadují dokončení aktualizací před provedením kaskádové změny.
  • Nikdy nevyvolá PropertyChanged událost, pokud se vlastnost nezmění. To znamená, že před vyvolání PropertyChanged události musíte porovnat staré a nové hodnoty.
  • Pokud inicializujete vlastnost, nikdy nezvyšujte PropertyChanged událost během konstruktoru modelu zobrazení. Ovládací prvky vázané na data v zobrazení nebudou v tuto chvíli odebírat oznámení o změnách.
  • Nikdy nezvyšujte více než jednu PropertyChanged událost se stejným argumentem názvu vlastnosti v rámci jednoho synchronního vyvolání veřejné metody třídy. Například vzhledem k NumberOfItems vlastnosti, jejíž backing store je _numberOfItems pole, pokud metoda zvýší _numberOfItems padesátkrát během provádění smyčky, měla by vyvolat oznámení o změně vlastnosti na NumberOfItems vlastnost pouze jednou, jakmile je všechna práce dokončena. U asynchronních metod vyvoláte PropertyChanged událost pro daný název vlastnosti v každém synchronním segmentu asynchronního řetězce pokračování.

Mobilní aplikace eShopOnContainers používá ExtendedBindableObject třídu k poskytování oznámení o změnách, která je znázorněna v následujícím příkladu kódu:

public abstract class ExtendedBindableObject : BindableObject  
{  
    public void RaisePropertyChanged<T>(Expression<Func<T>> property)  
    {  
        var name = GetMemberInfo(property).Name;  
        OnPropertyChanged(name);  
    }  

    private MemberInfo GetMemberInfo(Expression expression)  
    {  
        ...  
    }  
}

Třída Xamarin.Form BindableObject implementuje INotifyPropertyChanged rozhraní a poskytuje metodu OnPropertyChanged . Třída ExtendedBindableObject poskytuje metodu RaisePropertyChanged vyvolání oznámení o změně vlastnosti a v tom používá funkce poskytované BindableObject třídou.

Každá třída modelu zobrazení v mobilní aplikaci eShopOnContainers je odvozena od ViewModelBase třídy, která je zase odvozena od ExtendedBindableObject třídy. Proto každá třída modelu zobrazení používá metodu RaisePropertyChangedExtendedBindableObject ve třídě k poskytnutí oznámení o změně vlastnosti. Následující příklad kódu ukazuje, jak mobilní aplikace eShopOnContainers vyvolá oznámení o změně vlastnosti pomocí výrazu lambda:

public bool IsLogin  
{  
    get  
    {  
        return _isLogin;  
    }  
    set  
    {  
        _isLogin = value;  
        RaisePropertyChanged(() => IsLogin);  
    }  
}

Všimněte si, že použití výrazu lambda tímto způsobem zahrnuje malé náklady na výkon, protože výraz lambda se musí vyhodnotit pro každé volání. I když jsou náklady na výkon malé a obvykle by to nemělo vliv na aplikaci, náklady můžou narůstat, pokud existuje mnoho oznámení o změnách. Výhodou tohoto přístupu je ale to, že poskytuje podporu bezpečnosti typů kompilace a refaktoringu při přejmenování vlastností.

Interakce s uživatelským rozhraním pomocí příkazů a chování

V mobilních aplikacích se akce obvykle vyvolávají v reakci na akci uživatele, například kliknutí na tlačítko, které lze implementovat vytvořením obslužné rutiny události v souboru kódu za kódem. V modelu MVVM však odpovědnost za implementaci akce spočívá v modelu zobrazení a umístění kódu do kódu by se mělo vyhnout.

Příkazy poskytují pohodlný způsob, jak znázorňovat akce, které lze svázat s ovládacími prvky v uživatelském rozhraní. Zapouzdřují kód, který implementuje akci, a pomáhají oddělit od jeho vizuální reprezentace v zobrazení. Xamarin.Forms obsahuje ovládací prvky, které lze deklarativní připojit k příkazu, a tyto ovládací prvky vyvolá příkaz, když uživatel pracuje s ovládacím prvku.

Chování také umožňuje deklarativní připojení ovládacích prvků k příkazu. Chování se ale dá použít k vyvolání akce, která je přidružená k rozsahu událostí vyvolaných ovládacím prvku. Chování proto řeší mnoho stejných scénářů jako ovládací prvky s podporou příkazů a současně poskytuje větší míru flexibility a řízení. Kromě toho lze chování použít také k přidružení objektů příkazů nebo metod k ovládacím prvkům, které nebyly speciálně navrženy pro interakci s příkazy.

Implementace příkazů

Zobrazit modely obvykle zpřístupňují vlastnosti příkazů pro vazbu ze zobrazení, což jsou instance objektů, které implementují ICommand rozhraní. Řada ovládacích Xamarin.Forms prvků poskytuje Command vlastnost, která může být data svázaná s objektem ICommand poskytovaným modelem zobrazení. Rozhraní ICommand definuje metodu Execute , která zapouzdřuje samotnou operaci, metodu CanExecute , která označuje, zda lze vyvolat příkaz, a CanExecuteChanged událost, která nastane v případě, že dojde ke změnám, které ovlivňují, zda má být příkaz spuštěn. A Command třídy, které poskytuje Xamarin.Forms, implementují ICommand rozhraní, kde T je typ argumentů a ExecuteCanExecute.Command<T>

V modelu zobrazení by měl být objekt typu Command nebo Command<T> pro každou veřejnou vlastnost v modelu zobrazení typu ICommand. Konstruktor CommandCommand<T> vyžaduje objekt zpětného Action volání, který je volán při ICommand.Execute vyvolání metody. Metoda CanExecute je volitelný parametr konstruktoru a je Func to, který vrací bool.

Následující kód ukazuje, jak Command je instance, která představuje příkaz registru, vytvořena zadáním delegáta na metodu Register modelu zobrazení:

public ICommand RegisterCommand => new Command(Register);

Příkaz je vystaven zobrazení prostřednictvím vlastnosti, která vrací odkaz na .ICommand Execute Když je volána metoda objektuCommand, jednoduše přesměruje volání metody v modelu zobrazení prostřednictvím delegáta, který byl zadán v konstruktoruCommand.

Asynchronní metoda může být vyvolána příkazem pomocí async klíčových slov a await při zadávání delegáta Execute příkazu. To znamená, že zpětné volání je a Task mělo by být očekáváno. Například následující kód ukazuje, jak Command je instance, která představuje příkaz pro přihlášení, vytvořena zadáním delegáta na metodu SignInAsync modelu zobrazení:

public ICommand SignInCommand => new Command(async () => await SignInAsync());

Parametry lze předat do Execute a CanExecute akcí pomocí Command<T> třídy k vytvoření instance příkazu. Například následující kód ukazuje, jak Command<T> se instance používá k označení, že NavigateAsync metoda bude vyžadovat argument typu string:

public ICommand NavigateCommand => new Command<string>(NavigateAsync);

V obou třídách CommandCommand<T> je delegát metody CanExecute v každém konstruktoru volitelný. Pokud není zadán delegát, Command vrátí se pro trueCanExecute. Model zobrazení však může indikovat změnu stavu příkazu CanExecute voláním ChangeCanExecute metody na objektu Command . To způsobí vyvolání CanExecuteChanged události. Všechny ovládací prvky v uživatelském rozhraní, které jsou vázané na příkaz, pak aktualizují svůj povolený stav tak, aby odrážely dostupnost příkazu vázaného na data.

Vyvolání příkazů ze zobrazení

Následující příklad kódu ukazuje, jak Grid v LoginView vazbách na RegisterCommand třídu LoginViewModel pomocí TapGestureRecognizer instance:

<Grid Grid.Column="1" HorizontalOptions="Center">  
    <Label Text="REGISTER" TextColor="Gray"/>  
    <Grid.GestureRecognizers>  
        <TapGestureRecognizer Command="{Binding RegisterCommand}" NumberOfTapsRequired="1" />  
    </Grid.GestureRecognizers>  
</Grid>

Parametr příkazu lze také volitelně definovat pomocí CommandParameter vlastnosti. Typ očekávaného argumentu je zadán v Execute metodách cíle.CanExecute Když TapGestureRecognizer uživatel pracuje s připojeným ovládacím prvku, automaticky vyvolá cílový příkaz. Parametr příkazu, pokud je zadaný, se předá jako argument delegátovi příkazu Execute .

Implementace chování

Chování umožňuje přidání funkcí do ovládacích prvků uživatelského rozhraní bez nutnosti jejich podtřídy. Místo toho je funkce implementována ve třídě chování a připojena k ovládacímu prvku, jako by byla součástí samotného ovládacího prvku. Chování umožňuje implementovat kód, který byste normálně museli psát jako kód za sebou, protože přímo komunikuje s rozhraním API ovládacího prvku tak, aby bylo možné ho stručně připojit k ovládacímu prvku a zabalit pro opakované použití ve více než jednom zobrazení nebo aplikaci. V kontextu MVVM jsou chování užitečným přístupem pro připojení ovládacích prvků k příkazům.

Chování připojené k ovládacímu prvku prostřednictvím připojených vlastností se označuje jako připojené chování. Toto chování pak může použít vystavené rozhraní API prvku, ke kterému je připojeno k přidání funkcí do tohoto ovládacího prvku nebo jiných ovládacích prvků ve vizuálním stromu zobrazení. Mobilní aplikace eShopOnContainers obsahuje LineColorBehavior třídu, což je připojené chování. Další informace o tomto chování naleznete v tématu Zobrazení chyb ověření.

Chování Xamarin.Forms je třída, která je odvozena z Behavior nebo Behavior<T> třídy, kde T je typ ovládacího prvku, na který má chování platit. Tyto třídy poskytují OnAttachedTo a OnDetachingFrom metody, které by měly být přepsány tak, aby poskytovaly logiku, která se spustí při připojení k chování a odpojení od ovládacích prvků.

V mobilní aplikaci BindableBehavior<T> eShopOnContainers je třída odvozena od Behavior<T> třídy. Účelem BindableBehavior<T> třídy je poskytnout základní třídu pro Xamarin.Forms chování, které vyžadují BindingContext , aby chování bylo nastaveno na připojený ovládací prvek.

BindableBehavior<T> Třída poskytuje přepisovatelnou OnAttachedTo metodu, která nastavuje BindingContext chování, a přepisovatelnou OnDetachingFrom metoduBindingContext, která vyčistí . Kromě toho třída ukládá odkaz na připojený ovládací prvek ve AssociatedObject vlastnosti.

Mobilní aplikace eShopOnContainers obsahuje EventToCommandBehavior třídu, která spustí příkaz v reakci na událost, ke které dochází. Tato třída je odvozena od BindableBehavior<T> třídy, aby chování bylo možné vytvořit vazbu a spuštění ICommand určené vlastností Command při použití chování. Následující příklad kódu ukazuje EventToCommandBehavior třídu:

public class EventToCommandBehavior : BindableBehavior<View>  
{  
    ...  
    protected override void OnAttachedTo(View visualElement)  
    {  
        base.OnAttachedTo(visualElement);  

        var events = AssociatedObject.GetType().GetRuntimeEvents().ToArray();  
        if (events.Any())  
        {  
            _eventInfo = events.FirstOrDefault(e => e.Name == EventName);  
            if (_eventInfo == null)  
                throw new ArgumentException(string.Format(  
                        "EventToCommand: Can't find any event named '{0}' on attached type",   
                        EventName));  

            AddEventHandler(_eventInfo, AssociatedObject, OnFired);  
        }  
    }  

    protected override void OnDetachingFrom(View view)  
    {  
        if (_handler != null)  
            _eventInfo.RemoveEventHandler(AssociatedObject, _handler);  

        base.OnDetachingFrom(view);  
    }  

    private void AddEventHandler(  
            EventInfo eventInfo, object item, Action<object, EventArgs> action)  
    {  
        ...  
    }  

    private void OnFired(object sender, EventArgs eventArgs)  
    {  
        ...  
    }  
}

OnDetachingFrom Metody OnAttachedTo se používají k registraci a zrušení registrace obslužné rutiny události pro událost definovanou EventName ve vlastnosti. Když se událost aktivuje, OnFired vyvolá se metoda, která spustí příkaz.

Výhodou použití EventToCommandBehavior příkazu ke spuštění příkazu při spuštění události je, že příkazy mohou být přidruženy k ovládacím prvkům, které nebyly navrženy pro interakci s příkazy. Kromě toho se tím přesune kód zpracování událostí k zobrazení modelů, kde je možné testovat jednotky.

Vyvolání chování ze zobrazení

To EventToCommandBehavior je užitečné zejména pro připojení příkazu k ovládacímu prvku, který nepodporuje příkazy. ProfileView Například používá EventToCommandBehavior k provedení, když se ItemTapped událost aktivuje OrderDetailCommand na ListView seznamu objednávek uživatele, jak je znázorněno v následujícím kódu:

<ListView>  
    <ListView.Behaviors>  
        <behaviors:EventToCommandBehavior             
            EventName="ItemTapped"  
            Command="{Binding OrderDetailCommand}"  
            EventArgsConverter="{StaticResource ItemTappedEventArgsConverter}" />  
    </ListView.Behaviors>  
    ...  
</ListView>

Za běhu EventToCommandBehavior bude reagovat na interakci s .ListView Když je položka vybrána ListViewv bodě , ItemTapped událost se aktivuje, která spustí OrderDetailCommand v objektu ProfileViewModel. Ve výchozím nastavení se argumenty události události předávají příkazu. Tato data se převedou tak, jak se předávají mezi zdrojem a cílem převaděčem zadaným ve EventArgsConverter vlastnosti, který vrací Item z objektu ListViewItemTappedEventArgs. Proto při OrderDetailCommand spuštění se vybraná akce Order předá jako parametr registrované akci.

Další informace o chování naleznete v tématu Chování.

Shrnutí

Model-View-ViewModel (MVVM) pomáhá vyčistit obchodní a prezentační logiku aplikace od uživatelského rozhraní. Udržování čistého oddělení mezi logikou aplikace a uživatelským rozhraním pomáhá řešit řadu problémů s vývojem a může usnadnit testování, údržbu a vývoj aplikace. Může také výrazně zlepšit příležitosti opětovného použití kódu a umožňuje vývojářům a návrhářům uživatelského rozhraní snadněji spolupracovat při vývoji příslušných částí aplikace.

Pomocí vzoru MVVM je uživatelské rozhraní aplikace a podkladové prezentace a obchodní logiky oddělené do tří samostatných tříd: zobrazení, které zapouzdřuje uživatelské rozhraní a logiku uživatelského rozhraní; model zobrazení, který zapouzdřuje logiku a stav prezentace; a model, který zapouzdřuje obchodní logiku a data aplikace.