EntityFramework EntityState и привязка данных вместе с INotifyPropertyChanged

У меня есть представление WPF, которое отображает сущность «Отгрузка». У меня есть текстовый блок, содержащий звездочку, которая будет предупреждать пользователя о том, что запись изменена, но не сохранена. Первоначально я надеялся связать видимость этого (с преобразователем) со свойством Shipment.EntityState.

If value = EntityState.Modified Then
    Return Visibility.Visible
Else
    Return Visibility.Collapsed
End If

Свойство обновляется просто отлично, но представление не знает об изменении. Что мне нужно знать, так это то, как я могу заставить пользовательский интерфейс получать уведомления об изменении свойства. Если это невозможно сделать, есть ли хороший способ написать собственное свойство IsDirty, которое обрабатывает опровержения редактирования (т. е. если я изменяю значение свойства, а затем возвращаю его к исходному, оно не считается редактированием и состояние остается неизменной).

Любая помощь, как всегда, будет принята с благодарностью.

Кори


person CodeWarrior    schedule 08.04.2010    source источник


Ответы (2)


Я не вижу способа создать привязку XAML к существующему свойству, чтобы делать то, что вы пытаетесь сделать. Но вы можете написать собственное свойство IsDirty на основе EntityState; вы можете обновить это значение, подписавшись на событие PropertyChanged, вызванное базовым объектом EntityObject. Конечно, вам также нужно вызвать событие PropertyChanged для IsDirty (чтобы уведомить графический интерфейс) и проигнорировать это событие в вашем обработчике (чтобы предотвратить бесконечную рекурсию). Изменить: после вопроса OP добавлено следующее:

Вот как я это вижу, чтобы ответить на комментарий.

В класс отгрузки можно добавить:

public bool IsDirty { get { return EntityState == EntityState.Modified; } }

public Shipment() {
...
PropertyChanged += OnShipmentChanged;
}

private void OnShipmentChanged(object sender, PropertyChangedEventArgs pcea) {
    if (pcea.PropertyName != "IsDirty") { // prevent recursion
        OnPropertyChanged("IsDirty"); // notifies binding listener that the state has changed
    }
}

Ночью я подумал о другом способе, который состоит в том, чтобы создать множественную привязку для каждого свойства Shipment (что заменит все это понятие свойства IsDirty и фактически ответит на исходный вопрос). Это может иметь смысл, если есть всего пара свойств Shipment. Я бы сказал, что если их больше 3, мы должны забыть об этой идее.

person Timores    schedule 08.04.2010
comment
Как прослушивать событие, вызванное другим классом, например сущностью? Я попытался создать обработчик событий в классе сущности отгрузки, а затем в ViewModel, но безуспешно. Извините за вопрос, но я просто не знаю, и сегодня утром Google не добр ко мне. Кори - person CodeWarrior; 09.04.2010
comment
Я перевожу ваш приведенный выше код в VB.NET и застрял на этом :PropertyChanged += OnShipmentChanged;. Что это делает? Я понимаю, что += просто добавляет указанное значение к текущему значению, но отладчик принимает это во внимание. - person CodeWarrior; 09.04.2010
comment
Ой, извините за язык. += с событиями означает подписаться на событие. Я не очень хорошо разбираюсь в VB.NET, но думаю, что это эквивалентно: AddEventHandler(event, AddressOf processing_method) - person Timores; 10.04.2010

После того, как я немного поборолся с той же проблемой, вот решение, которое работает для меня. Допустим, у меня есть объект под названием Trip, созданный EF, мне просто нужно было расширить класс с помощью частичного класса, как показано ниже. Метод RaiseEntityStateChanged полезен, когда необходимо принудительно обновить свойство EntytyState, например, после вызова контекстного метода SaveChanges.

partial class Trip
{
   bool _forced = false;
   System.Data.EntityState _lastState;

   public Trip()
   {
     _lastState = EntityState;
     this.PropertyChanged += (s, e) => 
     {
       if (_lastState != this.EntityState && e.PropertyName != "EntityState" || _forced)
       {
          _forced = false;
          OnPropertyChanged("EntityState");
       }

       _lastState = this.EntityState;
    };
  }

  public virtual void RaiseEntityStateChanged()
  {
     _forced = true;
     OnPropertyChanged("EntityState");
  }
}
person MichelK7    schedule 17.11.2011