Używanie poleceń w modelu viewmodel
Pokazano, jak pobierać dane z modelu widoków do interfejsu użytkownika i jak można użyć powiązania dwukierunkowego w celu uzyskania danych z powrotem do modelu widoków.
Używanie powiązań dwukierunkowych, takich jak to, jest preferowanym sposobem reagowania na zmiany z interfejsu użytkownika za każdym razem, gdy zmiany danych . Wiele rzeczy, które można obsłużyć jako zdarzenia , można obsłużyć za pomocą powiązań dwukierunkowych i wzorca Model-View-ViewModel (MVVM). Inne przykłady to takie elementy jak Switch.IsToggled
i Slider.Value
, które można odzwierciedlić w modelu viewmodel jako wartość logiczną lub całkowitą bez konieczności używania zdarzeń.
Istnieją jednak pewne elementy, takie jak aktywacja Button
lub MenuItem
, które nie są bezpośrednio powiązane ze zmianą danych. Te interakcje nadal wymagają obsługi podobnej do zdarzeń. Ponieważ te składniki interfejsu użytkownika zwykle wywołują jakąś logikę z danymi, chcemy, aby ta logika w modelu widoków. Ale nie chcemy obsługiwać ich jako Clicked
i Selected
zdarzeń w kodzie, jeśli to możliwe. Chcemy, aby jak najwięcej było w modelu widoków, w ten sposób można to przetestować.
Korzystanie ze wzorca polecenia
Wiele kontrolek MAUI platformy .NET, które mają tego rodzaju obsługę interakcji, wiążą się z właściwością uwidaczniającą ICommand
interfejs. Ta właściwość najprawdopodobniej nosi nazwę Command
. Kontrolka Button
jest jednym z przykładów:
<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}" />
Kontrolka wie, kiedy wywołać polecenie. Na przykład przycisk wywołuje polecenie po naciśnięciu . Polecenie w tym przykładzie jest powiązane z właściwością GiveBonus
modelu viewmodel. Typ właściwości musi implementować ICommand
interfejs. Kod będzie wyglądać podobnie do poniższego przykładu:
public class EmployeeViewModel : INotifyPropertyChanged
{
public ICommand GiveBonusCommand {get; private set;}
...
}
Interfejs ICommand
ma metodę wywoływaną Execute
po naciśnięciu przycisku. W ten sposób funkcja ICommand.Execute
bezpośrednio zastępuje Button.Click
kod obsługi zdarzeń.
ICommand
Pełny interfejs ma jeszcze dwie metody: CanExecute
i CanExecuteChanged
służą do określania, czy kontrolka powinna być włączona, czy wyłączona.
Na przykład przycisk może pojawić się wygaszony, jeśli CanExecute
zwraca wartość false.
Oto jak ICommand
wygląda interfejs w języku C#:
public interface ICommand
{
bool CanExecute(object parameter);
void Execute(object parameter);
event EventHandler CanExecuteChanged;
}
Używanie klasy Command
Ten wzorzec polecenia umożliwia zachowanie czystego oddzielenia zachowania interfejsu użytkownika od implementacji interfejsu użytkownika. Jednak może to komplikować kod, jeśli musisz utworzyć oddzielną klasę w celu zaimplementowania każdej procedury obsługi zdarzeń.
Zamiast tworzyć kilka klas niestandardowych, które implementują interfejs, często używane Command
są klasy lub Command<T>
. Te klasy implementują ICommand
, ale uwidaczniają jego zachowanie jako właściwości w modelu widoków, które można ustawić. W ten sposób możemy zaimplementować właściwość opisaną GiveBonus
wcześniej całkowicie w naszej klasie 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.
}
}
W tym kodzie Execute
zachowanie jest udostępniane przez metodę GiveBonusExecute
. Funkcja CanExecute
jest dostarczana przez program GiveBonusCanExecute
. Delegaty do tych metod są przekazywane do konstruktora Command
. W tym przykładzie nie ma implementacji dla elementu CanExecuteChanged
.
Upraszczanie pracy z zestawem narzędzi MVVM Toolkit
Biblioteka zestawu narzędzi MVVM Toolkit zawiera implementacje ICommand
znane jako RelayCommand
i AsyncRelayCommand
. Dostarcza również generatory źródłowe, aby jeszcze bardziej uprościć ten kod. W poniższym przykładzie zostanie wygenerowane ustawienie zarówno metody do wywołania do wykonania, jak i wywołania w celu sprawdzenia, GiveBonusCommand
czy może zostać wykonane. Atrybut [RelayCommand]
jest używany w metodzie GiveBonus
i wygeneruje wartość GiveBonusCommand
. Ponadto, ustawiając CanExecute
właściwość atrybutu na nazwę metody, którą chcemy podłączyć do CanExecute
metody ICommand
, spowoduje wygenerowanie kodu w celu skonfigurowania go dla nas.
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;
}
}
Zestaw narzędzi MVVM obsługuje async
również metody, które są wspólne w programowaniu platformy .NET.
Polecenia z parametrami
Interfejs ICommand
akceptuje object
parametr dla CanExecute
metod i Execute
. Program .NET MAUI implementuje ten interfejs bez sprawdzania Command
typu za pośrednictwem klasy. Delegaty dołączane do polecenia muszą wykonać własne sprawdzanie typów, aby upewnić się, że został przekazany prawidłowy parametr. Program .NET MAUI udostępnia również implementację Command<T>
, w której ustawiono typ oczekiwanego parametru. Podczas tworzenia polecenia, które akceptuje pojedynczy typ parametru, użyj polecenia Command<T>
.
Kontrolki MAUI platformy .NET, które implementują wzorzec polecenia, zapewniają CommandParameter
właściwość . Ustawiając tę właściwość, można przekazać parametr do polecenia podczas wywoływania go za pomocą Execute
polecenia lub, gdy polecenie sprawdza metodę CanExecute
stanu.
W tym przykładzie wartość ciągu "25" jest wysyłana do polecenia:
<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}" CommandParameter="25" />
Polecenie musi interpretować i konwertować ten parametr ciągu. Istnieje wiele sposobów zapewnienia silnie typizowanego parametru.
Zamiast używać składni atrybutu do definiowania
CommandParameter
, użyj elementów XAML.<Button Text="Give Bonus" Command="{Binding GiveBonusCommand}"> <Button.CommandParameter> <x:Int32>25</x:Int32> </Button.CommandParameter> </Button>
Powiąż element z
CommandParameter
wystąpieniem poprawnego typu.Jeśli element
CommandParameter
jest powiązany z nieprawidłowym typem, zastosuj konwerter, aby przekonwertować wartość na poprawny typ.