Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Это ObservableObject базовый класс для объектов, наблюдаемых путем реализации INotifyPropertyChanged и INotifyPropertyChanging интерфейсов. Его можно использовать в качестве отправной точки для всех типов объектов, которые должны поддерживать уведомления об изменении свойств.
API платформы:
ObservableObject, ,TaskNotifierTaskNotifier<T>
Принцип работы
ObservableObject имеет следующие основные функции:
- Она предоставляет базовую реализацию для
INotifyPropertyChangedиINotifyPropertyChanging, предоставляя событияPropertyChangedиPropertyChangingсобытия. - Он предоставляет ряд
SetPropertyметодов, которые можно использовать для легкого задания значений свойств из типов, наследуемых отObservableObject, и автоматического вызова соответствующих событий. - Он предоставляет
SetPropertyAndNotifyOnCompletionметод, который аналогиченSetProperty, но с возможностью задатьTaskсвойства и автоматически вызывать события уведомлений при завершении назначенных задач. - Он предоставляет
OnPropertyChangedметоды иOnPropertyChangingметоды, которые можно переопределить в производных типах, чтобы настроить способ создания событий уведомлений.
Простое свойство
Ниже приведен пример реализации поддержки уведомлений для пользовательского свойства:
public class User : ObservableObject
{
private string name;
public string Name
{
get => name;
set => SetProperty(ref name, value);
}
}
SetProperty<T>(ref T, T, string) Предоставленный метод проверяет текущее значение свойства и обновляет его, если он отличается, а затем автоматически вызывает соответствующие события. Имя свойства автоматически фиксируется с помощью атрибута [CallerMemberName] , поэтому не нужно вручную указывать, какое свойство обновляется.
Упаковка не наблюдаемой модели
Распространенный сценарий, например при работе с элементами базы данных, заключается в создании модели оболочки "привязки", которая ретранслирует свойства модели базы данных и вызывает уведомления об изменении свойства при необходимости. Это также необходимо, если требуется внедрить поддержку уведомлений в модели, которые не реализуют INotifyPropertyChanged интерфейс. ObservableObject предоставляет выделенный метод, чтобы упростить этот процесс. В следующем примере User модель напрямую сопоставляет таблицу базы данных, не наследуя от ObservableObject:
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);
}
}
В этом случае мы используем перегрузку SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) . Сигнатура немного сложнее предыдущей. Это необходимо, чтобы код все еще был чрезвычайно эффективным, даже если у нас нет доступа к резервному полю, как в предыдущем сценарии. Мы можем подробно ознакомиться с каждой частью сигнатуры этого метода, чтобы понять роль различных компонентов:
TModel— это аргумент типа, указывающий тип модели, которую мы упаковаем. В этом случае это будет нашUserкласс. Обратите внимание, что нам не нужно явно указывать этот параметр. Компилятор C# будет автоматически выводить это путем вызоваSetPropertyметода.T— это тип свойства, которое мы хотим задать.TModelАналогично, это автоматически выводится.T oldValueявляется первым параметром, и в этом случае мы используемuser.Nameдля передачи текущего значения этого свойства, которое мы упаковаем.T newValue— это новое значение для задания свойства, и здесь мы передаваемvalueзначение, которое является входным значением в методе задания свойств.TModel model— это целевая модель, которую мы упаковаем, в этом случае мы передаваем экземпляр, хранящийся вuserполе.Action<TModel, T> callback— это функция, которая будет вызываться, если новое значение свойства отличается от текущего, а свойство должно быть задано. Это будет сделано этой функцией обратного вызова, которая получает в качестве входных данных целевую модель и новое значение свойства для задания. В этом случае мы просто назначаем входное значение (которое мы вызвалиn)Nameсвойству (выполняя).u.Name = nВажно избегать записи значений из текущей области и взаимодействовать только с теми, которые заданы в качестве входных данных обратному вызову, так как это позволяет компилятору C# кэшировать функцию обратного вызова и выполнять ряд улучшений производительности. Это связано с тем, что мы не только напрямую обращаются кuserполю здесь илиvalueпараметру в методе задания, но вместо этого мы используем только входные параметры для лямбда-выражения.
Метод SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) делает создание этих свойств оболочки чрезвычайно простым, так как он заботится о получении и настройке целевых свойств при предоставлении чрезвычайно компактного API.
Примечание.
По сравнению с реализацией этого метода с помощью выражений LINQ, в частности с помощью параметра типа Expression<Func<T>> вместо параметров состояния и обратного вызова, улучшения производительности, которые можно добиться таким образом, действительно важны. В частности, эта версия составляет ~200x быстрее, чем одна с помощью выражений LINQ, и не делает выделения памяти вообще.
Обработка Task<T> свойств
Если свойство является Task свойством, необходимо также вызвать событие уведомления после завершения задачи, чтобы привязки обновлялись в нужное время. Например, чтобы отобразить индикатор загрузки или другие сведения о состоянии операции, представленной задачей. ObservableObject имеет API для этого сценария:
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) Здесь метод будет заботиться об обновлении целевого поля, мониторинге новой задачи, если она присутствует, и вызове события уведомления при завершении этой задачи. Таким образом, можно просто привязаться к свойству задачи и получать уведомления при изменении его состояния. Это TaskNotifier<T> специальный тип, предоставляемый ObservableObject тем, что упаковывает целевой Task<T> экземпляр и включает необходимую логику уведомлений для этого метода. Тип TaskNotifier также доступен для использования непосредственно, если у вас есть только общий Task тип.
Примечание.
Метод SetPropertyAndNotifyOnCompletion предназначен для замены NotifyTaskCompletion<T> использования типа из Microsoft.Toolkit пакета. Если используется этот тип, его можно заменить только внутренним Task (или Task<TResult>) свойством, а затем SetPropertyAndNotifyOnCompletion метод можно использовать для задания его значения и повышения изменений уведомлений. Все свойства, NotifyTaskCompletion<T> предоставляемые типом, доступны непосредственно на Task экземплярах.
Примеры
- Ознакомьтесь с примером приложения (для нескольких платформ пользовательского интерфейса), чтобы просмотреть набор средств MVVM в действии.
- Дополнительные примеры можно найти в модульных тестах.
MVVM Toolkit