Связывание с ExpandoObject. PropertyChanged не работает
В моем приложении Windows Store у меня есть список, заполненный ExpandoObjects. Связывание данных отлично работает для начальных значений, но не для свойства изображения, которое я устанавливал асинхронно после загрузки файла:
public static async void Set<T>(this ExpandoObject thisObject, string property, Func<Task<T>> setter) {
var expando = thisObject as IDictionary<string, Object>;
if (!expando.ContainsKey(property)) {
expando.Add(property, null);
}
expando[property] = await setter.Invoke();
}
Подключение к событию PropertyChanged в ExpandoObject подтверждает, что он запущен для всех объектов.
Новое свойство привязано к объекту, и значение верное, но элементы в ListView не обновляются полностью.
Список содержит 14 объектов. Если я использую обычные типизированные объекты вместо ExpandoObjects и использую тот же параметр async свойства изображения, некоторые из 14 объектов обновляются в представлении (те, которые в настоящее время не видны). Если я реализую INotifyPropertyChanged в классе, все 14 обновляется.
Используя ExpandoObjects, я получаю точное поведение, как и с типизированными объектами без INPC: обновляемые элементы не обновляются.
Поэтому кажется, что PropertyChanged не работает с ExpandoObject и привязкой данных.
Он работает как в WPF, но не в App Store. См. Сравнение:
https://sites.google.com/site/moramatte/ExpandoComparison.zip?attredirects=0&d=1
Ответы
Ответ 1
Они не добавили механизм по умолчанию для привязки к динамическим объектам и вместо этого добавили новый интерфейс ICustomTypeProvider
. И этот интерфейс также не был добавлен в ExpandoObject, но с помощью expando вы должны использовать привязку индексатора, поскольку это IDictionary<string, object>
, который реализует INotifyPropertyChanged
.
<TextBlock Text="{Binding [Foo]}"/>
Ответ 2
Переходя к этому снова, я пришел к выводу, что привязка не работает для обновлений атрибутов (обработанных с помощью INotifyPropertyChanged) для WinRT/Win10 (Build 10240) при использовании ExpandoObjects.
INotifyCollectionChanged работает - поэтому списки объектов ExpandoObject обновляются по мере их изменения, но их свойства неправильно подключены с помощью привязки.
Один способ обхода - создать объект значения и сохранить его в каждом свойстве expandoobject:
public class ValueHolder : INotifyPropertyChanged
{
public ValueHolder(object v)
{
_value = v;
}
public event PropertyChangedEventHandler PropertyChanged;
private object _value;
public object Value
{
get { return _value; }
set {
if (_value != value)
{
_value = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Value"));
}
}
}
}
}
Затем я могу успешно связывать и получать обновления из свойств в expandoobjects следующим образом:
<TextBlock Text='{Binding Path=Attribute1.Value }' MinWidth='20'/>
Я назначаю новые свойства следующим образом:
(theList[0] as dynamic).Attribute1 = new ValueHolder("a1");
Я обновляю такие свойства:
var listitem = (thelist[0] as dynamic);
listitem.Attribute1.Value = "UPDATE";