Как работает ObservableCollection/INotifyPropertyChange при изменении объекта

У меня есть ситуация, когда в одной модели представления обновляются некоторые свойства объекта. В другой модели представления я подписываюсь на сообщение, а затем обновляю коллекцию этим новым объектом, например:

WeakReferenceMessenger.Default.Register<UpdatedMessage>(this, (r, m) =>
{
    if (this.MyObjects != null)
    {
        var myObj = this.MyObjects.FirstOrDefault(x => x.MyObject == m.Value.MyObject);

        if (myObj != null)
        {
            myObj = m.Value;
            //myObj.MyProperty = m.Value.MyProperty; //this updates UI, above line does not
        }
    }
});

Несмотря на то, что MyObject реализует INotifyPropertyChanged, а MyObjects является ObservableCollection<MyObject>, пользовательский интерфейс WPF не обновляется.

Однако, если я обновлю свойство на myObj вот так:

myObj.MyProperty = m.Value.MyProperty;

Пользовательский интерфейс WPF обновляется.

Я предполагаю, что это связано с тем, что изменение объекта не вызывает событие PropertyChanged (поскольку это не добавление/обновление/изменение порядка в коллекции), в отличие от изменения свойства объекта.

Итак, два вопроса:

  1. Правильно ли я понимаю, почему это не работает?
  2. Как лучше всего справиться с этой ситуацией, когда любые/все свойства могут измениться? Я хочу избежать необходимости вручную записывать обновления для каждого свойства объекта (которые затем сломаются, если будет добавлено новое свойство, и я забуду обновить это сообщение).

Я не вижу изменений в упомянутом объекте в вашем коде, поэтому никакое событие не запускается.

Ralf 15.07.2024 16:39

Вероятно, вам нужно обменять объект в MyObjects, а не просто изменить экземпляр, на который указывает myObj.

Ralf 15.07.2024 16:40

Да, я так и сделал вывод. var myObj — ссылка на объект в коллекции. Когда я это делаю myObj = m.Value;, я меняю объект ссылки на локальные переменные, а не обновляю объект в коллекции. Поэтому мой вопрос заключался в том, как мне добиться обновления всех свойств объекта в коллекции без необходимости записывать его для каждого объекта.

WSC 15.07.2024 16:41

Если коллекция представляет собой ObservableCollection, вы можете заменить myObj на m.Value. Однако вам нужно найти его индекс, int index = MyObjects.IndexOf(myObj);. Тогда пишите MyObjects[index] = m.Value;

Clemens 15.07.2024 16:47

Если порядок элементов не имеет значения, напишите MyObjects.Remove(myObj); MyObjects.Add(m.Value);

Clemens 15.07.2024 16:49

Я попробовал опцию Add/Remove, но поскольку она изменила порядок, это немного напутало со стороны пользовательского интерфейса. О замене на индекс не думал, попробую.

WSC 15.07.2024 16:53

Хорошо, да, использование IndexOf сработало. Спасибо. Если захотите написать ответ, я отмечу как принятый.

WSC 15.07.2024 16:56

Вместо вызова MyObjects.FirstOrDefault, а затем MyObjects.IndexOf, вы можете найти индекс напрямую с помощью простого цикла for или while.

Clemens 15.07.2024 17:06
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Выражение

myObj = m.Value;

только изменяет значение локальной переменной и, следовательно, не обновляет пользовательский интерфейс.

Вам придется заменить объект в коллекции MyObjects, возможно, наиболее эффективно с помощью простого цикла for:

if (MyObjects != null)
{
    for (int i = 0; i < MyObjects.Count; i++)
    {
        if (MyObjects[i].MyProperty == m.Value.MyProperty)
        {
            MyObjects[i] = m.Value;
            break;
        }
    }
}

Другие вопросы по теме