Opdrachten gebruiken in een viewmodel
U hebt gezien hoe u gegevens uit uw viewmodels naar uw gebruikersinterface kunt ophalen en hoe u tweerichtingsbindingen kunt gebruiken om gegevens terug te krijgen in uw viewmodels.
Het gebruik van bindingen in twee richtingen is de voorkeurswijze om te reageren op wijzigingen in de gebruikersinterface wanneer gegevens worden gewijzigd. Veel dingen die we als gebeurtenissen zouden verwerken, kunnen worden verwerkt met behulp van bindingen in twee richtingen en het MVVM-patroon (Model-View-ViewModel). Andere voorbeelden zijn zaken als Switch.IsToggled
en Slider.Value
, die in ons viewmodel kunnen worden weerspiegeld als een booleaanse waarde of geheel getal, zonder dat u gebeurtenissen hoeft te gebruiken.
Maar er zijn enkele dingen, zoals een Button
of MenuItem
activering, die niet rechtstreeks zijn gekoppeld aan het wijzigen van gegevens. Voor deze interacties is nog steeds gebeurtenis-achtige verwerking vereist. Omdat deze UI-onderdelen meestal een soort logica aanroepen met de gegevens, willen we die logica in het viewmodel. Maar we willen ze niet verwerken als Clicked
en Selected
gebeurtenissen in de code-behind, indien mogelijk. We willen zoveel mogelijk in het viewmodel zijn, op die manier is het testbaar.
Het opdrachtpatroon gebruiken
Veel van de .NET MAUI-besturingselementen met dit soort interactieondersteuning binden aan een eigenschap die een ICommand
interface beschikbaar maakt. Deze eigenschap heeft waarschijnlijk de naam Command
. Het Button
besturingselement is één voorbeeld:
<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}" />
Het besturingselement weet wanneer de opdracht moet worden aangeroepen. Met een knop wordt bijvoorbeeld de opdracht aangeroepen wanneer u op de knop drukt. De opdracht in dit voorbeeld is gebonden aan de GiveBonus
eigenschap van het viewmodel. Het eigenschapstype moet de ICommand
interface implementeren. De code ziet er ongeveer als volgt uit:
public class EmployeeViewModel : INotifyPropertyChanged
{
public ICommand GiveBonusCommand {get; private set;}
...
}
De ICommand
interface heeft een Execute
methode die wordt aangeroepen wanneer de knop wordt ingedrukt. Op deze manier vervangt Button.Click
de ICommand.Execute
gebeurtenisafhandelingscode rechtstreeks.
De volledige ICommand
interface heeft nog twee methoden: CanExecute
en CanExecuteChanged
die worden gebruikt om te bepalen of een besturingselement moet worden ingeschakeld of uitgeschakeld.
Een knop kan bijvoorbeeld grijs worden weergegeven als CanExecute
deze onwaar retourneert.
ICommand
De interface ziet er als volgt uit in C#:
public interface ICommand
{
bool CanExecute(object parameter);
void Execute(object parameter);
event EventHandler CanExecuteChanged;
}
De opdrachtklasse gebruiken
Met dit opdrachtpatroon kunt u een schone scheiding van het gedrag van de gebruikersinterface behouden van de implementatie van de gebruikersinterface. Maar het kan uw code bemoeilijken als u een afzonderlijke klasse moet maken om elke gebeurtenis-handler te implementeren.
In plaats van verschillende aangepaste klassen te maken die de interface implementeren, is het gebruikelijk om te gebruiken Command
of Command<T>
. Deze klassen implementeren ICommand
, maar maken het gedrag zichtbaar als eigenschappen in uw viewmodel dat u kunt instellen. Op deze manier kunnen we de GiveBonus
eerder beschreven eigenschap volledig implementeren in onze viewmodel-klasse:
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.
}
}
In deze code wordt het Execute
gedrag geleverd door de methode GiveBonusExecute
. En CanExecute
wordt geleverd door GiveBonusCanExecute
. Gedelegeerden aan deze methoden worden doorgegeven aan de Command
constructor. In dit voorbeeld is er geen implementatie voor CanExecuteChanged
.
Vereenvoudigen met de MVVM Toolkit
De MVVM Toolkit-bibliotheek bevat implementaties van ICommand
bekende en AsyncRelayCommand
RelayCommand
. Het levert ook brongeneratoren om deze code verder te vereenvoudigen. In het volgende voorbeeld wordt zowel GiveBonusCommand
de methode gegenereerd die moet worden aangeroepen om uit te voeren als om aan te roepen om te zien of het kan worden uitgevoerd. Het [RelayCommand]
kenmerk wordt gebruikt voor de GiveBonus
methode en genereert het GiveBonusCommand
. Door de CanExecute
eigenschap op het kenmerk in te stellen op de naam van de methode die we willen koppelen aan de methode van de CanExecute
ICommand
methode, wordt de code gegenereerd om deze voor ons in te stellen.
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;
}
}
De MVVM Toolkit verwerkt async
ook methoden, die gebruikelijk zijn in .NET-programmering.
Opdrachten met parameters
De ICommand
interface accepteert een object
parameter voor de CanExecute
en Execute
methoden. .NET MAUI implementeert deze interface zonder typecontrole via de Command
klasse. De gemachtigden die u aan de opdracht koppelt, moeten hun eigen typecontrole uitvoeren om ervoor te zorgen dat de juiste parameter wordt doorgegeven. .NET MAUI biedt ook de Command<T>
implementatie waar u het verwachte type parameter instelt. Wanneer u een opdracht maakt die één type parameter accepteert, gebruikt u Command<T>
.
.NET MAUI-besturingselementen waarmee het opdrachtpatroon wordt geïmplementeerd, bieden de CommandParameter
eigenschap. Door deze eigenschap in te stellen, kunt u een parameter doorgeven aan de opdracht wanneer u deze aanroept of Execute
wanneer de opdracht de methode controleert op de CanExecute
status.
In dit voorbeeld wordt de tekenreekswaarde 25 verzonden naar de opdracht:
<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}" CommandParameter="25" />
De opdracht moet die tekenreeksparameter interpreteren en converteren. Er zijn veel manieren om een sterk getypte parameter op te geven.
Gebruik XAML-elementen in plaats van kenmerksyntaxis om te definiëren
CommandParameter
.<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}"> <Button.CommandParameter> <x:Int32>25</x:Int32> </Button.CommandParameter> </Button>
Bind de
CommandParameter
aan een exemplaar van het juiste type.Als de
CommandParameter
waarde afhankelijk is van het onjuiste type, past u een conversieprogramma toe om de waarde te converteren naar het juiste type.