Použití příkazů v modelu viewmodel

Dokončeno

Viděli jste, jak získat data z modelů viewmodelů do uživatelského rozhraní a jak můžete pomocí obousměrné vazby získat data zpět do svých modelů viewmodelů.

Použití obousměrných vazeb, jako je to preferovaný způsob reakce na změny z uživatelského rozhraní při každé změně dat . Mnoho věcí, které bychom zpracovávali jako události , je možné zpracovat pomocí obousměrných vazeb a MVVM. Další příklady jsou například Switch.IsToggled a Slider.Valuekteré se dají v našem modelu viewmodel promítnout jako logická nebo celočíselná hodnota, aniž byste museli používat události.

Existují ale některé věci, například aktivace Button , MenuItem které nejsou přímo svázané se změnou dat. Tyto interakce stále vyžadují zpracování podobné událostem. Vzhledem k tomu, že tyto komponenty uživatelského rozhraní obvykle vyvolávají určitou logiku s daty, chceme tuto logiku v modelu viewmodel. Ale nechceme je zpracovávat jako Clicked události Selected v kódu, pokud je to možné. Chceme, aby bylo co nejvíce v modelu viewmodel, tak je to testovatelné.

Použití vzoru příkazu

Mnoho ovládacích prvků .NET MAUI, které mají tento druh interakce, podporují vazbu na vlastnost, která zveřejňuje ICommand rozhraní. Tato vlastnost je s největší pravděpodobností pojmenována Command. Tlačítko je jedním z příkladů:

<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}" />

Ovládací prvek ví, kdy má příkaz vyvolat. Například tlačítko vyvolá příkaz, když se stiskne. Příkaz v tomto příkladu je vázán na GiveBonusCommand vlastnost viewmodel. Typ vlastnosti musí implementovat ICommand rozhraní. Kód by vypadal přibližně takto:

public class EmployeeViewModel : INotifyPropertyChanged
{
    public ICommand GiveBonusCommand {get; private set;}
    ...
}

Rozhraní ICommand má metodu Execute , která se volá při kliknutí na tlačítko. Tímto způsobem ICommand.Execute přímo nahradí Button.Click kód zpracování událostí.

Úplné ICommand rozhraní má dvě další metody: CanExecute a CanExecuteChanged které se používají k určení, zda se má ovládací prvek zobrazit povolený nebo zakázaný.

Například tlačítko se může zobrazit šedě, pokud CanExecute vrátí hodnotu false.

ICommand Toto rozhraní vypadá v jazyce C#:

public interface ICommand
{
    bool CanExecute(object parameter);
    void Execute(object parameter);
    event EventHandler CanExecuteChanged;
}

Použití třídy Command

Tento vzor příkazu umožňuje udržovat čisté oddělení chování uživatelského rozhraní od implementace uživatelského rozhraní. Pokud ale potřebujete vytvořit samostatnou třídu pro implementaci každé obslužné rutiny událostí, může to komplikovat váš kód.

Místo vytváření několika vlastních tříd, které implementují rozhraní, je běžné použít Command nebo Command<T>. Tyto třídy implementují ICommand , ale zpřístupňují jeho chování jako vlastnosti v modelu viewmodel, který můžete nastavit. To vám umožní implementovat GiveBonusCommand vlastnost popsanou dříve zcela v rámci naší třídy viewmodel:

public class EmployeeViewModel : INotifyPropertyChanged
{
    public ICommand GiveBonusCommand {get; private set;}
    public EmployeeViewModel(Employee model)
    {
        GiveBonusCommand = new Command(GiveBonusExecute, GiveBonusCanExecute)
    }

    void GiveBonusExecute()
    {
        //logic for giving bonus
    }

    bool GiveBonusCanExecute()
    {
        //logic for deciding if "give bonus" button should be enabled.
    }
}

V tomto kódu Execute je chování poskytováno metodou GiveBonusExecute. A CanExecute je poskytována GiveBonusCanExecute. Delegáty na tyto metody jsou předány konstruktoru Command . V tomto příkladu neexistuje žádná implementace pro CanExecuteChanged.

Zjednodušení pomocí MVVM Toolkit

Knihovna MVVM Toolkit obsahuje implementace ICommand známé jako RelayCommand a AsyncRelayCommand. Poskytuje také generátory zdrojů pro další zjednodušení tohoto kódu. V následujícím příkladu GiveBonusCommand se vygeneruje nastavení metody pro volání ke spuštění a volání, aby bylo možné zjistit, zda je možné provést. Atribut [RelayCommand] se používá v GiveBonus metodě a vygeneruje GiveBonusCommand. Navíc nastavením CanExecute vlastnosti atributu na název metody, kterou chceme připojit k CanExecute metodě ICommand, vygeneruje kód pro nastavení pro nás.

public partial class EmployeeViewModel : ObservableObject
{
    public EmployeeViewModel(Employee model)
    {
    }

    [RelayCommand(CanExecute = nameof(GiveBonusCanExecute))]
    void GiveBonus()
    {
        //logic for giving bonus
    }

    bool GiveBonusCanExecute()
    {
        //logic for deciding if "give bonus" button should be enabled.
        return true;
    }
}

Sada MVVM Toolkit také zpracovává async metody, které jsou běžné v programování .NET.

Příkazy s parametry

Rozhraní ICommand přijímá object parametr pro metody CanExecute a Execute metody. Rozhraní .NET MAUI implementuje toto rozhraní bez kontroly typu prostřednictvím Command třídy. Delegáti, které připojíte k příkazu, musí provést vlastní kontrolu typů, aby se zajistilo, že je předán správný parametr. Rozhraní .NET MAUI také poskytuje implementaci Command<T> , ve které nastavíte typ očekávaného parametru. Při vytváření příkazu, který přijímá jeden typ parametru, použijte Command<T>.

Ovládací prvky .NET MAUI, které implementují vzor příkazu, poskytují CommandParameter vlastnost. Nastavením této vlastnosti můžete předat parametr příkazu při vyvolání pomocí Execute, nebo při kontrole CanExecute stavu metody.

V tomto příkladu se řetězcová hodnota 25 odešle do příkazu:

<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}" CommandParameter="25" />

Příkaz by potřeboval interpretovat a převést tento parametr řetězce. Existuje mnoho způsobů, jak poskytnout parametr silného typu.

  • Místo použití syntaxe atributů k definování CommandParameterpoužijte elementy XAML.

    <Button Text="Give Bonus" Command="{Binding GiveBonusCommand}">
        <Button.CommandParameter>
            <x:Int32>25</x:Int32>
        </Button.CommandParameter>
    </Button>
    
  • Vytvořte vazbu na CommandParameter instanci správného typu.

  • CommandParameter Pokud je vázán na nesprávný typ, použijte převaděč pro převod hodnoty na správný typ.

Kontrola znalostí

1.

Jaký je účel ICommand rozhraní?

2.

Jak můžou Command třídy nebo Command<T> třídy zjednodušit používání ICommand rozhraní?

3.

Jaká je role vlastnosti v ovládacích CommandParameter prvcích .NET MAUI?