У меня есть ситуация, когда в одной модели представления обновляются некоторые свойства объекта. В другой модели представления я подписываюсь на сообщение, а затем обновляю коллекцию этим новым объектом, например:
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 (поскольку это не добавление/обновление/изменение порядка в коллекции), в отличие от изменения свойства объекта.
Итак, два вопроса:
Вероятно, вам нужно обменять объект в MyObjects, а не просто изменить экземпляр, на который указывает myObj.
Да, я так и сделал вывод. var myObj — ссылка на объект в коллекции. Когда я это делаю myObj = m.Value;, я меняю объект ссылки на локальные переменные, а не обновляю объект в коллекции. Поэтому мой вопрос заключался в том, как мне добиться обновления всех свойств объекта в коллекции без необходимости записывать его для каждого объекта.
Если коллекция представляет собой ObservableCollection, вы можете заменить myObj на m.Value. Однако вам нужно найти его индекс, int index = MyObjects.IndexOf(myObj);. Тогда пишите MyObjects[index] = m.Value;
Если порядок элементов не имеет значения, напишите MyObjects.Remove(myObj); MyObjects.Add(m.Value);
Я попробовал опцию Add/Remove, но поскольку она изменила порядок, это немного напутало со стороны пользовательского интерфейса. О замене на индекс не думал, попробую.
Хорошо, да, использование IndexOf сработало. Спасибо. Если захотите написать ответ, я отмечу как принятый.
Вместо вызова MyObjects.FirstOrDefault, а затем MyObjects.IndexOf, вы можете найти индекс напрямую с помощью простого цикла for или while.





Выражение
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;
}
}
}
Я не вижу изменений в упомянутом объекте в вашем коде, поэтому никакое событие не запускается.