Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Jest ObservableObject to klasa bazowa dla obiektów, które można zaobserwować przez zaimplementowanie INotifyPropertyChanged interfejsów i INotifyPropertyChanging . Może służyć jako punkt wyjścia dla wszystkich rodzajów obiektów, które muszą obsługiwać powiadomienia o zmianie właściwości.
Interfejsy API platformy:
ObservableObject, ,TaskNotifierTaskNotifier<T>
Jak to działa
ObservableObject ma następujące główne funkcje:
- Zapewnia on podstawową implementację elementu
INotifyPropertyChangediINotifyPropertyChanging, uwidaczniając zdarzeniaPropertyChangediPropertyChanging. - Udostępnia szereg
SetPropertymetod, których można użyć do łatwego ustawiania wartości właściwości z typów dziedziczynych zObservableObjectklasy i w celu automatycznego zgłaszania odpowiednich zdarzeń. - Zapewnia metodę
SetPropertyAndNotifyOnCompletion, która jest analogiczna doSetPropertymetody , ale z możliwością ustawianiaTaskwłaściwości i automatycznego zgłaszania zdarzeń powiadomień po zakończeniu przypisanych zadań. - Uwidacznia
OnPropertyChangedmetody iOnPropertyChanging, które można zastąpić w typach pochodnych, aby dostosować sposób zgłaszania zdarzeń powiadomień.
Właściwość Simple
Oto przykład implementacji obsługi powiadomień dla właściwości niestandardowej:
public class User : ObservableObject
{
private string name;
public string Name
{
get => name;
set => SetProperty(ref name, value);
}
}
Podana SetProperty<T>(ref T, T, string) metoda sprawdza bieżącą wartość właściwości i aktualizuje ją, jeśli jest inna, a następnie automatycznie zgłasza odpowiednie zdarzenia. Nazwa właściwości jest automatycznie przechwytywana za pomocą atrybutu [CallerMemberName] , dlatego nie trzeba ręcznie określać, która właściwość jest aktualizowana.
Zawijanie nieoserwowalnego modelu
Typowy scenariusz, na przykład podczas pracy z elementami bazy danych, polega na utworzeniu modelu zawijania "możliwego do powiązania", który przekazuje właściwości modelu bazy danych i zgłasza zmiany właściwości w razie potrzeby. Jest to również konieczne, gdy chcesz wstrzyknąć obsługę powiadomień do modeli, które nie implementują interfejsu INotifyPropertyChanged . ObservableObject Udostępnia dedykowaną metodę, aby ten proces był prostszy. W poniższym przykładzie User model jest bezpośrednio mapowaniem tabeli bazy danych bez dziedziczenia z ObservableObjectklasy :
public class ObservableUser : ObservableObject
{
private readonly User user;
public ObservableUser(User user) => this.user = user;
public string Name
{
get => user.Name;
set => SetProperty(user.Name, value, user, (u, n) => u.Name = n);
}
}
W tym przypadku używamy SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) przeciążenia. Podpis jest nieco bardziej złożony niż poprzedni — jest to konieczne, aby kod nadal był bardzo wydajny, nawet jeśli nie mamy dostępu do pola zapasowego, takiego jak w poprzednim scenariuszu. Możemy szczegółowo zapoznać się z każdą częścią tego podpisu metody, aby zrozumieć rolę różnych składników:
TModeljest argumentem typu wskazującym typ modelu, który opakowujemy. W tym przypadku będzie to naszaUserklasa. Pamiętaj, że nie musimy jawnie określać tego elementu — kompilator języka C# wywnioskuje to automatycznie, wywołując metodęSetProperty.Tjest typem właściwości, którą chcemy ustawić. Podobnie jakTModelw przypadku metody , jest to automatycznie wnioskowane.T oldValuejest pierwszym parametrem, a w tym przypadku używamyuser.Namepolecenia , aby przekazać bieżącą wartość tej właściwości, którą opakowujemy.T newValuejest nową wartością ustawioną na właściwość , a tutaj przekazujemyvaluewartość wejściową w ustawieniu właściwości.TModel modelto model docelowy, który opakowujemy, w tym przypadku przekazujemy wystąpienie przechowywane wuserpolu.Action<TModel, T> callbackto funkcja, która zostanie wywołana, jeśli nowa wartość właściwości jest inna niż bieżąca, a właściwość musi zostać ustawiona. Będzie to wykonywane przez tę funkcję wywołania zwrotnego, która otrzymuje jako dane wejściowe modelu docelowego i nową wartość właściwości do ustawienia. W tym przypadku po prostu przypisujemy wartość wejściową (o nazwien) doNamewłaściwości (wykonując polecenieu.Name = n). Ważne jest, aby uniknąć przechwytywania wartości z bieżącego zakresu i korzystać tylko z tych podanych jako dane wejściowe wywołania zwrotnego, ponieważ umożliwia to kompilatorowi języka C# buforowanie funkcji wywołania zwrotnego i wykonywanie szeregu ulepszeń wydajności. Jest to spowodowane tym, że nie tylko uzyskujemy bezpośredni dostęp douserpola tutaj lubvalueparametru w zestawie, ale zamiast tego używamy tylko parametrów wejściowych dla wyrażenia lambda.
Metoda SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) sprawia, że tworzenie tych właściwości opakowujących jest niezwykle proste, ponieważ dba zarówno o pobieranie, jak i ustawianie właściwości docelowych przy jednoczesnym zapewnieniu niezwykle kompaktowego interfejsu API.
Uwaga
W porównaniu z implementacją tej metody przy użyciu wyrażeń LINQ, w szczególności za pomocą parametru typu Expression<Func<T>> zamiast parametrów stanu i wywołania zwrotnego, ulepszenia wydajności, które można osiągnąć w ten sposób, są naprawdę znaczące. W szczególności ta wersja jest ok. 200x szybsza niż ta używająca wyrażeń LINQ i w ogóle nie wykonuje żadnych alokacji pamięci.
Obsługa Task<T> właściwości
Jeśli właściwość jest właściwością Task , należy również zgłosić zdarzenie powiadomienia po zakończeniu zadania, aby powiązania były aktualizowane w odpowiednim czasie. Np. aby wyświetlić wskaźnik ładowania lub inne informacje o stanie operacji reprezentowanej przez zadanie. ObservableObject ma interfejs API dla tego scenariusza:
public class MyModel : ObservableObject
{
private TaskNotifier<int>? requestTask;
public Task<int>? RequestTask
{
get => requestTask;
set => SetPropertyAndNotifyOnCompletion(ref requestTask, value);
}
public void RequestValue()
{
RequestTask = WebService.LoadMyValueAsync();
}
}
SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>, Task<T>, string) W tym miejscu metoda zajmie się aktualizowaniem pola docelowego, monitorowaniem nowego zadania, jeśli jest obecne, i wywoływaniem zdarzenia powiadomienia po zakończeniu tego zadania. W ten sposób można po prostu powiązać z właściwością zadania i otrzymywać powiadomienia o zmianie stanu. Jest TaskNotifier<T> to specjalny typ uwidoczniony przez ObservableObject to zawijanie wystąpienia docelowego Task<T> i umożliwia niezbędną logikę powiadomień dla tej metody. Typ TaskNotifier jest również dostępny do użycia bezpośrednio, jeśli masz tylko ogólne Task .
Uwaga
Metoda SetPropertyAndNotifyOnCompletion ma zastąpić użycie NotifyTaskCompletion<T> typu z Microsoft.Toolkit pakietu. Jeśli ten typ był używany, można go zastąpić tylko właściwością wewnętrzną Task (lub Task<TResult>), a następnie SetPropertyAndNotifyOnCompletion można użyć metody w celu ustawienia jej wartości i wywołania zmian powiadomień. Wszystkie właściwości uwidocznione przez NotifyTaskCompletion<T> typ są dostępne bezpośrednio w Task wystąpieniach.
Przykłady
- Zapoznaj się z przykładową aplikacją (dla wielu struktur interfejsu użytkownika), aby zobaczyć, jak działa zestaw narzędzi MVVM Toolkit.
- Więcej przykładów można również znaleźć w testach jednostkowych.
MVVM Toolkit