Предисловие:
Вопрос здесь кажется мне довольно сложным. Я не знаю, возможно ли это. Пожалуйста, если вам интересно, прочитайте вводный текст, а затем код в предоставленной ссылке (вопрос на форуме по-французски, но код читабелен), обязательно поймите это, потому что я go довольно глубже, чем после. Проблема касается отслеживания изменений в иерархии классов моделей и широко использует события и делегатов. Приятного чтения!
Я создаю приложение, которое управляет супермаркетом, и многие клиенты получают доступ к акциям разных рынков (например, расположенных в разных местах).
Супермаркет содержит на многих рынках каждый рынок содержит (ObservableCollection) некоторые свойства (например, название) и ObservableCollection полок, каждая полка содержит (все еще один тип коллекции) некоторые продукты и некоторые свойства, и, наконец, каждый продукт содержит некоторые свойства.
Моя проблема в том, что когда кто-то меняет, например, TextBox, отображающий имя первого рынка, благодаря привязке данных, модель (первый рынок в супермаркете ObservableCollection) изменяется; и я хотел бы знать об изменении в проекте MVVM решения, и я хотел бы затем вызвать веб-сервис, который изменит базу данных, в которой хранится модель.
Поскольку у меня нет предыдущего значения модели при изменении TextBox, а затем при изменении модели, я не могу сравнить «старую» модель с «новой», чтобы увидеть различия. Вторая идея состоит в том, чтобы отслеживать изменения (каждый класс в модели реализует INotifyPropertyChanged), и для этого я нашел подсказку: см. этот пост на французском языке (код в ответе) , который показывает, как ObservableCollection может вызвать событие, когда один из его элементов изменен (и событие отслеживает измененный элемент). При условии, что элемент имеет уникальный идентификатор, я могу отслеживать измененные элементы, а затем вызывать веб-службу для изменения базы данных с изменением только элемента.
Но для этого мне нужно изменить модель ( заменив все ObservableCollections на MyObservableCollections), и я думаю, что это не рекомендуется, модель не должна содержать код.
Зная, что я использую MVVM (а проект MVVM не имеет ссылки на проект WPF), что является наилучшей практикой в этом случае? Должен ли я изменить модель? Это очень сложно сделать?
спасибо
РЕДАКТИРОВАТЬ
Я закодировал вещь, но у меня есть некоторые проблемы.
Чтобы иметь Вот четкие идеи: 2 нижних уровня иерархии модели:
Продукты в каждом супермаркете:
[DataContract]
public class ProduitMagasin : ElementSupermarche
{
[Key]
[DataMember]
public int ProduitMagasinId { set; get; }
private string _Nom;
[DataMember]
public string Nom
{
set
{
if (value == _Nom) return;
_Nom = value;
OnPropertyChanged();
}
get => _Nom;
}
private int _Quantite;
[DataMember]
public int Quantite
{
set
{
if (value == _Quantite) return;
_Quantite = value;
OnPropertyChanged();
}
get => _Quantite;
}
}
ничего особенного, за исключением того, что ElementSupermarche реализует INotifyPropertyChanged.
Эти продукты находятся в ObservableCollectionTrack, который является моей улучшенной версией MyObservableCollection в приведенной выше ссылке http.
здесь находится класс полок:
[DataContract]
public class Rayon : ElementSupermarche
{
public delegate void ItemPropertyChangedHandler(object Sender, ObservableCollectionTrackPropertyChangedEventArgs e);
public event ItemPropertyChangedHandler CollectionPropertyChanged;
[Key]
[DataMember]
public int RayonId { set; get; }
private string _Nom;
[DataMember]
public string Nom
{
set
{
if (value == _Nom) return;
_Nom = value;
OnPropertyChanged();
}
get => _Nom;
}
[DataMember]
public virtual ObservableCollectionTrack<ProduitMagasin> Produits { set; get; }
//voir si il est appelé par new Rayon(){params}
public Rayon()
{
Produits.CollectionPropertyChanged += new ObservableCollectionTrack<ProduitMagasin>.ItemPropertyChangedHandler(TrackHandler);
}
private void TrackHandler(object Sender, ObservableCollectionTrackPropertyChangedEventArgs e)
{
CollectionPropertyChanged(Sender, e);
}
}
Вот класс ObservableCollectionTrack:
public class ObservableCollectionTrack<T> : ObservableCollection<T>
where T : INotifyPropertyChanged
{
public delegate void ItemPropertyChangedHandler(object Sender, ObservableCollectionTrackPropertyChangedEventArgs e);
public event ItemPropertyChangedHandler CollectionPropertyChanged;
public ObservableCollectionTrack()
: base()
{
base.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ObservableCOllectionTrack_CollectionChanged);
}
void ObservableCOllectionTrack_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
foreach (T item in e.OldItems)
{
//Removed items
item.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
item.CollectionPropertyChanged += new ObservableCollectionTrack<ProduitMagasin>.ItemPropertyChangedHandler(TrackHandler); <------------------------
}
}
else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
foreach (T item in e.NewItems)
{
//Added items
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
item.CollectionPropertyChanged += new ObservableCollectionTrack<ProduitMagasin>.ItemPropertyChangedHandler(TrackHandler);
}
}
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (CollectionPropertyChanged != null)
{
CollectionPropertyChanged(this, new ObservableCollectionTrackPropertyChangedEventArgs(sender, e));
}
}
private void TrackHandler(object Sender, ObservableCollectionTrackPropertyChangedEventArgs e)
{
CollectionPropertyChanged(Sender, e);
}
}
//Arguments de l'évébement CollectionPropertyChanged de la classe ObservableCollectionTrack
public class ObservableCollectionTrackPropertyChangedEventArgs : PropertyChangedEventArgs
{
public Object Item { get; set; }
public ObservableCollectionTrackPropertyChangedEventArgs(Object Item, string propertyName)
: base(propertyName)
{
this.Item = Item;
}
public ObservableCollectionTrackPropertyChangedEventArgs(Object Item, PropertyChangedEventArgs e)
: base(e.PropertyName)
{
this.Item = Item;
}
}
Идея состоит в том, что коллекция отслеживает события PropertyChanged, вызванные ее элементами, а затем вызывает CollectionPropertyChanged. Но есть проблема: пожалуйста, следуйте за мной по потоку: продукт изменился; он вызывает PropertyChanged, который вызывает в переменной Produits событие CollectionPropertyChanged; Затем экземпляр Rayon инициирует событие CollectionPropertyChanged (оно повторно отправляет то же самое событие), но экземпляр Rayon находится в самой коллекции ObservableCollectionTrack, поэтому делается вывод, что для повторного повторного вызова событие CollectionPropertyChanged должно быть подписано самой ObservableCollectionTrack!
Отсюда и строка со стрелкой в ObservableCollectionTrack (приведена выше). Но, учитывая это, код не работает: элемент не объявляет обработку ObservableCollectionTrack. и если я пытаюсь добавить, что T должен наследовать от ObservableCollectionTrack, я получаю это:
Он не может преобразовать переменную в ее правильный тип! Это связано с рекурсивностью? Нужно ли преобразовывать ObservableCollectionTrack в интерфейс, более или менее как INotifyPropertyChanged? Можно ли прогрессировать и достичь этой функциональности (поскольку все почти закодировано)?
спасибо.