Använda kommandon i en viewmodel
Du såg hur du hämtar data från dina viewmodels till ditt användargränssnitt och hur du kan använda dubbelriktad bindning för att få tillbaka data till dina viewmodels.
Att använda dubbelriktade bindningar på det sättet är det bästa sättet att reagera på ändringar från användargränssnittet när data ändras. Många saker som vi skulle hantera som händelser kan hanteras med hjälp av tvåvägsbindningar och MVVM-mönstret (Model-View-ViewModel). Andra exempel är saker som Switch.IsToggled
och Slider.Value
, som kan återspeglas i vår viewmodel som ett booleskt värde eller heltalsvärde, utan att behöva använda händelser.
Men det finns vissa saker, till exempel en Button
eller MenuItem
aktivering, som inte är direkt kopplade till att ändra data. Dessa interaktioner kräver fortfarande händelseliknande hantering. Eftersom dessa gränssnittskomponenter vanligtvis anropar någon form av logik med data, vill vi ha den logiken i viewmodel. Men vi vill inte hantera dem som Clicked
och Selected
händelser i koden bakom, om möjligt. Vi vill att så mycket som möjligt ska vara i viewmodel, på det sättet är det testbart.
Använd kommandomönstret
Många av .NET MAUI-kontrollerna som har den här typen av interaktion stöder bindning till en egenskap som exponerar ett ICommand
gränssnitt. Den här egenskapen heter Command
troligen . Kontrollen Button
är ett exempel:
<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}" />
Kontrollen vet när kommandot ska anropas. En knapp anropar till exempel kommandot när den trycks ned. Kommandot i det här exemplet är bundet GiveBonus
till egenskapen viewmodel. Egenskapstypen måste implementera ICommand
gränssnittet. Koden skulle se ut ungefär så här:
public class EmployeeViewModel : INotifyPropertyChanged
{
public ICommand GiveBonusCommand {get; private set;}
...
}
Gränssnittet ICommand
har en Execute
metod som anropas när knappen trycks in. På så sätt ICommand.Execute
ersätter direkt händelsehanteringskoden Button.Click
.
Det fullständiga ICommand
gränssnittet har ytterligare två metoder: CanExecute
och CanExecuteChanged
som används för att avgöra om en kontroll ska visas aktiverad eller inaktiverad.
En knapp kan till exempel se nedtonad ut om CanExecute
den returnerar false.
ICommand
Så här ser gränssnittet ut i C#:
public interface ICommand
{
bool CanExecute(object parameter);
void Execute(object parameter);
event EventHandler CanExecuteChanged;
}
Använda klassen Command
Med det här kommandomönstret kan du upprätthålla en ren separation av användargränssnittets beteende från implementeringen av användargränssnittet. Men det kan komplicera koden om du behöver skapa en separat klass för att implementera varje händelsehanterare.
I stället för att skapa flera anpassade klasser som implementerar gränssnittet är det vanligt att använda Command
eller Command<T>
. Dessa klasser implementerar ICommand
men exponerar dess beteende som egenskaper i din vymodell som du kan ange. På så sätt kan vi implementera egenskapen GiveBonus
som beskrevs tidigare helt i vår viewmodel-klass:
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.
}
}
I den här koden tillhandahålls Execute
beteendet av metoden GiveBonusExecute
. Och CanExecute
tillhandahålls av GiveBonusCanExecute
. Ombud till dessa metoder skickas till Command
konstruktorn. I det här exemplet finns det ingen implementering för CanExecuteChanged
.
Förenkla med MVVM Toolkit
MVVM Toolkit-biblioteket innehåller implementeringar av ICommand
kända som RelayCommand
och AsyncRelayCommand
. Den tillhandahåller också källgeneratorer för att förenkla den här koden ytterligare. I följande exempel GiveBonusCommand
genereras inställningen både den metod som ska anropas för att köras och för att anropa för att se om den kan köras. Attributet [RelayCommand]
används på GiveBonus
metoden och genererar GiveBonusCommand
. Genom att ange CanExecute
egenskapen för attributet till namnet på den metod som vi vill ansluta till CanExecute
metoden ICommand
för genererar den dessutom koden för att konfigurera detta åt oss.
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;
}
}
MVVM Toolkit hanterar async
också metoder som är vanliga i .NET-programmering.
Kommandon med parametrar
Gränssnittet ICommand
accepterar en object
parameter för CanExecute
metoderna och Execute
. .NET MAUI implementerar det här gränssnittet utan någon typkontroll via Command
klassen. De ombud som du bifogar till kommandot måste utföra sin egen typkontroll för att säkerställa att rätt parameter skickas. .NET MAUI tillhandahåller också implementeringen Command<T>
där du anger vilken typ av parameter som förväntas. När du skapar ett kommando som accepterar en enskild typ av parameter använder du Command<T>
.
.NET MAUI-kontroller som implementerar kommandomönstret tillhandahåller CommandParameter
egenskapen. Genom att ange den här egenskapen kan du skicka en parameter till kommandot när du anropar den med Execute
, eller när kommandot kontrollerar CanExecute
metoden för status.
I det här exemplet skickas strängvärdet "25" till kommandot:
<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}" CommandParameter="25" />
Kommandot skulle behöva tolka och konvertera strängparametern. Det finns många sätt att tillhandahålla en starkt typad parameter.
I stället för att använda attributsyntax för att definiera
CommandParameter
använder du XAML-element.<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}"> <Button.CommandParameter> <x:Int32>25</x:Int32> </Button.CommandParameter> </Button>
CommandParameter
Binda till en instans av rätt typ.CommandParameter
Om är bunden till den felaktiga typen använder du en konverterare för att konvertera värdet till rätt typ.