Korzystanie z modelu widoków
Po zapoznaniu się ze składnikami tworzącym wzorzec MVVM prawdopodobnie okazało się, że model i widok były łatwe do zdefiniowania. Przyjrzyjmy się, jak używać modelu viewmodel, aby lepiej zdefiniować swoją rolę we wzorcu.
Uwidacznianie właściwości interfejsu użytkownika
Podobnie jak w poprzednim przykładzie, modele widoków zwykle opierają się na modelach dla większości danych i dowolnej logiki biznesowej. Jest to jednak model widoków, który formatuje, konwertuje i wzbogaca dane w dowolny sposób, jaki wymaga bieżący widok.
Formatowanie przy użyciu modelu viewmodel
Przedstawiono już przykład formatowania z czasem urlopu. Formatowanie dat, kodowanie znaków i serializacja to przykłady formatowania danych z modelu przez model viewmodel.
Konwertowanie przy użyciu modelu viewmodel
Często model dostarcza informacje w sposób pośredni. Ale model widoków może to naprawić. Załóżmy na przykład, że chcesz pokazać na ekranie, czy pracownik jest przełożonym. Ale nasz Employee
model nie mówi nam, że bezpośrednio. Zamiast tego musisz wywnioskować ten fakt na podstawie tego, czy osoba ma do nich inne raporty. Załóżmy, że model ma tę właściwość:
public IList<Employee> DirectReports
{
get
{
...
}
}
Jeśli lista jest pusta, możesz wywnioskować, że nie jest to Employee
nadzorca. W tym przypadku EmployeeViewModel
zawiera właściwość IsSupervisor
, która zapewnia tę logikę:
public bool IsSupervisor => _model.DirectReports.Any();
Wzbogacanie przy użyciu modelu viewmodel
Czasami model może podać tylko identyfikator powiązanych danych. Może też być konieczne przejście do kilku klas modelu, aby skorelować dane wymagane dla jednego ekranu. Model widoków zapewnia idealne miejsce do wykonywania tych zadań. Załóżmy, że chcesz wyświetlić wszystkie projekty, którymi obecnie zarządza pracownik. Te dane nie są częścią Employee
klasy modelu. Dostęp do niego można uzyskać, przeglądając klasę CompanyProjects
modelu. Nasz EmployeeViewModel
, jak zawsze, ujawnia swoją pracę jako własność publiczną:
public IEnumerable<string> ActiveProjects => CompanyProjects.All
.Where(p => p.Owner == _model.Id && p.IsActive)
.Select(p => p.Name);
Używanie właściwości przekazywania z modelem viewmodel
Często model widoków potrzebuje dokładnie właściwości, którą zapewnia model. W przypadku tych właściwości model viewmodel po prostu przekazuje dane za pośrednictwem:
public string Name
{
get => _model.Name;
set => _model.Name = value;
}
Ustawianie zakresu modelu widoków
Możesz użyć modelu widoków na dowolnym poziomie, na którym znajduje się widok. Strona zwykle ma model widoku, ale może więc podglądać strony. Jedną z typowych przyczyn zagnieżdżonych modelu widoków jest wyświetlenie strony ListView
na stronie. Lista zawiera model widoków, który reprezentuje kolekcję, taką jak EmployeeListViewModel
. Każdy element na liście jest elementem EmployeeViewModel
.
Często zdarza się również, że model widoku najwyższego poziomu przechowuje dane i stan dla całej aplikacji, ale nie jest skojarzony z żadną konkretną stroną. Taki model widoku jest często używany do obsługi elementu "aktywny". ListView
Rozważmy właśnie opisany przykład. Gdy użytkownik wybierze wiersz pracownika, ten pracownik reprezentuje bieżący element. Jeśli użytkownik przejdzie do strony szczegółów lub wybierze przycisk paska narzędzi po wybraniu tego wiersza, akcja lub ekran powinien być wyświetlany dla tego pracownika. Elegancki sposób obsługi tego scenariusza polega na tym ListView.SelectItem
, że dane są powiązane z właściwością, do których może również uzyskiwać dostęp pasek narzędzi lub strona szczegółów. Umieszczenie tej właściwości na centralnym modelu widokowym działa dobrze.
Identyfikowanie, kiedy należy ponownie używać modeli widoków z widokami
Sposób definiowania relacji między modelem widoku a modelem i między modelem widoków i widokiem jest dyktowany bardziej przez wymagania aplikacji niż przez reguły. Celem modelu widoku jest zapewnienie widoku struktury i danych, których potrzebuje. Powinno to kierować decyzjami na temat "jak duży", aby określić zakres modelu widoków.
Modele widoków często ściśle odzwierciedlają strukturę klasy modelu i mają relację jeden do jednego z tą klasą. Pokazano przykład wcześniej z EmployeeViewModel
tym opakowanym i rozszerzonym pojedynczym Employee
wystąpieniem. Ale nie zawsze jest to relacja jeden do jednego. Jeśli model widoku został zaprojektowany tak, aby zapewnić, czego potrzebuje widok, możesz zamiast tego przedstawić coś HRDashboardViewModel
podobnego do omówienia działu kadr, który nie ma jawnej relacji z żadnym modelem, ale może używać danych z dowolnej klasy modelu.
Podobnie może się okazać, że modele widoków i widoki często mają relację jeden do jednego. Ale to również niekoniecznie jest tak. Pomyślmy ponownie o tym ListView
, że pokazuje wiersz dla każdego pracownika. Po wybraniu jednego z wierszy przejdź do strony szczegółów pracownika.
Na stronie listy znajduje się model widoku z kolekcją. Jak wspomniano wcześniej, ta kolekcja może być kolekcją EmployeeViewModel
obiektów. A gdy użytkownik wybierze wiersz, EmployeeViewModel
wystąpienie może zostać przekazane do obiektu EmployeeDetailPage
. Strona szczegółów może używać jej EmployeeViewModel
jako .BindingContext
Ten scenariusz może być doskonałą okazją do ponownego użycia modelu viewmodel. Należy jednak pamiętać, że modele widoków mają na celu zapewnienie potrzeb widoku. W niektórych przypadkach możesz chcieć użyć oddzielnych modeli widoków, nawet jeśli są one oparte na tej samej klasie modelu. W tym przykładzie ListView
wiersze prawdopodobnie będą potrzebować znacznie mniej informacji niż pełna strona szczegółów. W przypadku pobierania danych strona szczegółów wymaga dużej ilości narzutu, warto mieć oba EmployeeListRowViewModel
modele, EmployeeDetailViewModel
które obsłużą te widoki.
Model obiektu Viewmodel
Użycie klasy bazowej, która implementuje INotifyPropertyChanged
, oznacza, że nie trzeba ponownie wdrażać interfejsu na każdym modelu widoków. Rozważmy aplikację KADR zgodnie z opisem w poprzedniej części tego modułu szkoleniowego. Klasa EmployeeViewModel
zaimplementowała INotifyPropertyChanged
interfejs i dostarczyła metodę pomocnika o nazwie OnPropertyChanged
w celu wywołania PropertyChanged
zdarzenia. Inne modele widoków w projekcie, takie jak te, które opisują zasoby przypisane do pracownika, również wymagają INotifyPropertyChanged
pełnej integracji z widokiem.
Biblioteka zestawu narzędzi MVVM, część zestawu narzędzi .NET Community Toolkit , jest kolekcją standardowych, samodzielnych, lekkich typów, które zapewniają początkową implementację do tworzenia nowoczesnych aplikacji przy użyciu wzorca MVVM.
Zamiast pisać własną klasę bazową modelu viewmodel, dziedziczysz z klasy zestawu narzędzi ObservableObject
, która zapewnia wszystko, czego potrzebujesz do klasy bazowej modelu viewmodel. Element EmployeeViewModel
można uprościć z następujących funkcji:
using System.ComponentModel;
public class EmployeeViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private Employee _model;
public string Name
{
get {...}
set
{
_model.Name = value;
OnPropertyChanged(nameof(Name))
}
}
protected void OnPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Do następującego kodu:
using Microsoft.Toolkit.Mvvm.ComponentModel;
public class EmployeeViewModel : ObservableObject
{
private string _name;
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
}
Kod można jeszcze bardziej uprościć przy użyciu generatorów źródłowych dostarczonych przez zestaw narzędzi MVVM Toolkit. Tworząc klasę partial
i dodając element [ObservableProperty]
do zmiennej private
, właściwość Name
publiczna jest generowana przy użyciu odpowiednich powiadomień o zmianie właściwości.
using Microsoft.Toolkit.Mvvm.ComponentModel;
public partial class EmployeeViewModel : ObservableObject
{
[ObservableProperty]
private string _name;
}
Zestaw narzędzi MVVM Jest dystrybuowany za pośrednictwem CommunityToolkit.Mvvm
pakietu NuGet.