private int _id;
public int Id
{
get => _id;
set
{
if (value == _id) return;
_id = value;
OnPropertyChanged;
}
}
Проделайте аналогичную работу со всеми остальными свойствами в классе и снова запустите приложение. Выберите автомобиль и щелкните на кнопке Change Color. Изменение немедленно отобразится в пользовательском интерфейсе. Первая проблема решена!
Использование операции nameof
В версии C# 6 появилась операция nameof
, которая возвращает строковое имя переданного ей элемента. Ее можно применять в вызовах метода OnPropertyChanged
внутри блоков set
, например:
public string Color
{
get { return _color; }
set
{
if (value == _color) return;
_color = value;
OnPropertyChanged(nameof(Color));
}
}
Обратите внимание на то, что в случае использования операции nameof
удалять атрибут [CallerMemberName]
из метода OnPropertyChanged
необязательно (хотя он становится излишним). В конце концов, выбор между применением операции nameof
или атрибута CallerMemberName
зависит от личных предпочтений.
Наблюдаемые коллекции
Следующей проблемой, которую необходимо решить, является обновление пользовательского интерфейса при изменении содержимого коллекции, что достигается путем реализации интерфейса INotifyCollectionChanged
. Подобно INotifyPropertyChanged
данный интерфейс открывает доступ к единственному событию CollectionChanged
. В отличие от INotifyPropertyChanged
реализация интерфейса INotifyCollectionChanged
вручную предполагает больший объем действий, чем просто вызов метода в блоке set
свойства. Понадобится создать реализацию полного списка объектов и генерировать событие CollectionChanged
каждый раз, когда он изменяется.
Использование класса ObservableCollection
К счастью, существует намного более легкий способ, чем создание собственных классов коллекций. Класс ObservableCollection
реализует интерфейсы INotifyCollectionChanged
, INotifyPropertyChanged
и Collection
и входит в состав .NET Core. Никакой дополнительной работы делать не придется. Чтобы продемонстрировать его применение, добавьте оператор using
для пространства имен System.Collections.ObjectModel
и модифицируйте закрытое поле _cars
следующим образом:
private readonly IList
new ObservableCollection
Снова запустите приложение и щелкните на кнопке Add Car. Новые записи будут должным образом появляться.
Реализация флага изменения
Еще одним преимуществом наблюдаемых моделей является способность отслеживать изменения состояния. Отслеживать флаги изменения (т.е. когда изменяется одно и более значений объекта) в WPF довольно легко. Добавьте в класс Car
свойство типа bool
по имени IsChanged
. Внутри его блока set
вызовите метод OnPropertyChanged
, как поступали с другими свойствами класса Car
.
private bool _isChanged;
public bool IsChanged {
get => _isChanged;
set
{
if (value == _isChanged) return;
_isChanged = value;
OnPropertyChanged;
}
}
Свойство IsChanged
необходимо устанавливать в true
внутри метода OnPropertyChanged
. Важно не устанавливать свойство IsChanged
в true
в случае изменения его самого, иначе сгенерируется исключение переполнения стека! Модифицируйте метод OnPropertyChanged
следующим образом (здесь используется описанная ранее операция nameof
):
protected virtual void OnPropertyChanged(
[CallerMemberName] string propertyName = "")
{
if (propertyName != nameof(IsChanged))
{
IsChanged = true;
}
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
}
Откройте файл MainWindow.xaml
и добавьте в DetailsGrid
дополнительный элемент RowDefinition
. Поместите в конец элемента Grid
показанную ниже разметку, которая содержит элементы управления Label
и Checkbox
, привязанные к свойству IsChanged
:
Margin="10,0,0,0" IsEnabled="False" IsChecked="{Binding Path=IsChanged}" />
Бьерн Страуструп , Бьёрн Страуструп , Валерий Федорович Альмухаметов , Ирина Сергеевна Козлова
Программирование, программы, базы данных / Базы данных / Программирование / Учебная и научная литература / Образование и наука / Книги по IT