private int _id;

public int Id

{

  get => _id;

  set

  {

    if (value == _id) return;

    _id = value;

    OnPropertyChanged;

  }

}

Проделайте аналогичную работу со всеми остальными свойствами в классе и снова запустите приложение. Выберите автомобиль и щелкните на кнопке Change Color. Изменение немедленно отобразится в пользовательском интерфейсе. Первая проблема решена!

<p id="AutBody_Root1263"><strong>Использование операции nameof</strong></p>

 В версии 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 зависит от личных предпочтений.

<p id="AutBody_Root1264"><strong>Наблюдаемые коллекции</strong></p>

 Следующей проблемой, которую необходимо решить, является обновление пользовательского интерфейса при изменении содержимого коллекции, что достигается путем реализации интерфейса INotifyCollectionChanged. Подобно INotifyPropertyChanged данный интерфейс открывает доступ к единственному событию CollectionChanged. В отличие от INotifyPropertyChanged реализация интерфейса INotifyCollectionChanged вручную предполагает больший объем действий, чем просто вызов метода в блоке set свойства. Понадобится создать реализацию полного списка объектов и генерировать событие CollectionChanged каждый раз, когда он изменяется.

<p id="AutBody_Root1265"><strong>Использование класса ObservableCollection<t></t></strong></p>

К счастью, существует намного более легкий способ, чем создание собственных классов коллекций. Класс ObservableCollection реализует интерфейсы INotifyCollectionChanged, INotifyPropertyChanged и Collection и входит в состав .NET Core. Никакой дополнительной работы делать не придется. Чтобы продемонстрировать его применение, добавьте оператор using для пространства имен System.Collections.ObjectModel и модифицируйте закрытое поле _cars следующим образом:

private readonly IList _cars =

  new ObservableCollection;

Снова запустите приложение и щелкните на кнопке Add Car. Новые записи будут должным образом появляться.

<p id="AutBody_Root1266"><strong>Реализация флага изменения</strong></p>

Еще одним преимуществом наблюдаемых моделей является способность отслеживать изменения состояния. Отслеживать флаги изменения (т.е. когда изменяется одно и более значений объекта) в 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}" />

Перейти на страницу:

Похожие книги