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