Używanie poleceń w modelu widoku
- {liczbaMinut} minut
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 jest preferowanym sposobem reagowania na zmiany z interfejsu użytkownika za każdym razem, gdy zmieniają się dane. Wiele rzeczy, które zwykle traktujemy jako zdarzenia, można obsłużyć wykorzystując powiązania dwukierunkowe i wzorzec 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 jak w przypadku zdarzeń. Ponieważ te składniki interfejsu użytkownika zwykle wprowadzają pewną logikę związaną z danymi, chcemy, aby ta logika była umieszczona w ViewModelu. Ale nie chcemy obsługiwać ich jako zdarzeń Clicked i Selected w pliku code-behind, jeśli to możliwe. Chcemy, aby jak najwięcej było w modelu widoku, tak aby można było to przetestować.
Korzystanie ze wzorca polecenia
Wiele kontrolek MAUI platformy .NET, które mają tego rodzaju interakcję, obsługuje powiązanie z właściwością udostępniają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ć interfejs ICommand. 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ę Execute, która jest wywoływana 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żywa się Command 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 zapewniane 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 GiveBonusCommand, które ustawia zarówno metodę do wywołania w celu wykonania, jak i metodę do sprawdzenia, czy można ją wykonać. Atrybut [RelayCommand] jest używany w metodzie GiveBonus i wygeneruje wartość GiveBonusCommand. Ponadto, ustawienie właściwości CanExecute w atrybucie na nazwę metody, którą chcemy powiązać z metodą CanExecuteICommand, spowoduje wygenerowanie kodu, aby ją skonfigurować.
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 również obsługuje async metody powszechnie używane w programowaniu .NET.
Polecenia z parametrami
Interfejs ICommand akceptuje object parametr dla CanExecute metod i Execute . Program .NET MAUI implementuje ten interfejs bez żadnego sprawdzania typu za pomocą klasy Command. 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, posiadają właściwość CommandParameter. Ustawiając tę właściwość, można przekazać parametr do polecenia podczas wywoływania go za pomocą Execute, lub gdy polecenie sprawdza metodę CanExecute dla statusu.
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 na zapewnienie 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
CommandParameterwystąpieniem poprawnego typu.Jeśli element
CommandParameterjest powiązany z nieprawidłowym typem, zastosuj konwerter, aby przekonwertować wartość na poprawny typ.