private readonly IList<Car> _cars =
new ObservableCollection<Car>();
Снова запустите приложение и щелкните на кнопке 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:
<Label Grid.Column="0" Grid.Row="5" Content="Is Changed"/>
<CheckBox Grid.Column="1" Grid.Row="5" VerticalAlignment="Center"
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})
Margin="10,0,0,0" IsEnabled="False" IsChecked="{Binding Path=IsChanged}" />
Если вы запустите приложение прямо сейчас, то увидите, что каждая отдельная запись отображается как измененная, хотя пока ничего не изменялось! Дело в том, что во время создания объекта устанавливаются значения свойств, а установка любых значений приводит к вызову метода OnPropertyChanged(), который и устанавливает свойство IsChanged объекта. Чтобы устранить проблему, установите свойство IsChanged в false последним в коде инициализации объекта. Откройте файл MainWindow.xaml.cs и модифицируйте код создания списка:
_cars.Add(
new Car {Id = 1, Color = "Blue", Make = "Chevy",
PetName = "Kit", <b>IsChanged = false</b>});
_cars.Add(
new Car {Id = 2, Color = "Red", Make = "Ford",
PetName = "Red Rider", <b>IsChanged = </b><b>false</b>});
Снова запустите приложение, выберите автомобиль и щелкните на кнопке Change Color. Флажок Is Changed (Изменено) становится отмеченным наряду с изменением цвета.
Обновление источника через взаимодействие с пользовательским интерфейсом
Во время выполнения приложения можно заметить, что при вводе в текстовых полях флажок Is Changed не становится отмеченным до тех пор, пока фокус не покинет элемент управления, где производился ввод. Причина кроется в свойстве UpdateSourceTrigger привязок элементов TextBox.
Свойство UpdateSourceTrigger определяет, какое событие (изменение значения, переход фокуса и т.д.) является основанием для обновления пользовательским интерфейсом лежащих в основе данных. Перечисление UpdateSourceTrigger принимает значения, описанные в табл. 28.1.
Стандартным событием обновления для элементов управления TextBox является LostFocus. Измените его на PropertyChanged, модифицировав привязку для элемента TextBox, который отвечает за ввод цвета:
<TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Path=Color,
UpdateSourceTrigger=PropertyChanged}" />
Если вы запустите приложение и начнете ввод в текстовом поле Color (Цвет), то флажок Is Changed немедленно отметится. Может возникнуть вопрос о том, почему для элементов управления TextBox в качестве стандартного выбрано значение LostFocus. Дело в том, что проверка достоверности (рассматриваемая вскоре) для модели запускается в сочетании с UpdateSourceTrigger. В случае TextBox это может потенциально вызывать ошибки, которые будут постоянно возникать до тех пор, пока пользователь не введет корректное значение. Например, если правила проверки достоверности не разрешают вводить в элементе TextBox менее пяти символов, тогда сообщение об ошибке будет отображаться при каждом нажатии клавиши, пока пользователь не введет пять или более символов. В таких случаях с обновлением источника лучше подождать до момента, когда пользователь переместит фокус из элемента TextBox (завершив изменение текста).