Свойство зависимостей ObservableCollection не обновляется, когда элемент в коллекции удален
У меня есть прикрепленное свойство типа ObservableCollection на элементе управления. Если я добавляю или удаляю элементы из коллекции, ui не обновляется. Однако, если я заменю коллекцию на новую, ViewModel обновит ui.
Может ли кто-нибудь дать мне пример того, что мне нужно сделать в объекте Dependency, чтобы он мог обрабатывать изменения внутри коллекции?
Часть объекта зависимости приведена ниже:
public class RadCalendarBehavior : DependencyObject
{
private static void OnSpecialDaysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var calendar = d as RadCalendar;
if (e.NewValue != null)
{
calendar.DayTemplateSelector = new SpecialDaySelector((ObservableCollection<DateTime>)e.NewValue, GetSpecialDayTemplate(d));
}
}
public static ObservableCollection<DateTime> GetSpecialDays(DependencyObject obj)
{
return (ObservableCollection<DateTime>)obj.GetValue(SpecialDaysProperty);
}
public static void SetSpecialDays(DependencyObject obj, ObservableCollection<DateTime> value)
{
obj.SetValue(SpecialDaysProperty, value);
}
public static readonly DependencyProperty SpecialDaysProperty =
DependencyProperty.RegisterAttached("SpecialDays", typeof(ObservableCollection<DateTime>), typeof(RadCalendarBehavior), new UIPropertyMetadata(null, OnSpecialDaysChanged));
}
}
Я понимаю, что мне нужно зарегистрировать, что коллекция изменилась, но я не уверен, как это сделать в свойстве зависимости
Ответы
Ответ 1
Изменение в коллекции не вызовет обратный вызов OnSpecialDaysChanged
, поскольку значение свойства зависимостей не изменилось. Если вам необходимо отреагировать на обнаружение изменений в коллекции, вам необходимо обработать событие CollectionChanged
вручную:
private static void OnSpecialDaysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var calendar = d as RadCalendar;
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged)e.OldValue;
// Unsubscribe from CollectionChanged on the old collection
coll.CollectionChanged -= SpecialDays_CollectionChanged;
}
if (e.NewValue != null)
{
var coll = (ObservableCollection<DateTime>)e.NewValue;
calendar.DayTemplateSelector = new SpecialDaySelector(coll, GetSpecialDayTemplate(d));
// Subscribe to CollectionChanged on the new collection
coll.CollectionChanged += SpecialDays_CollectionChanged;
}
}
private static void SpecialDays_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// handle CollectionChanged
}
Ответ 2
Это просто добавить к ответу Томаса. В моем коде я взаимодействую с свойствами DependencyObject, создавая локальный объект-обработчик, как показано ниже:
private static void OnSpecialDaysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var action = new NotifyCollectionChangedEventHandler(
(o, args) =>
{
var calendar = d as RadCalendar;
if (calendar!= null)
{
// play with calendar properties/methods
}
});
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged)e.OldValue;
// Unsubscribe from CollectionChanged on the old collection
coll.CollectionChanged -= action;
}
if (e.NewValue != null)
{
var coll = (ObservableCollection<DateTime>)e.NewValue;
// Subscribe to CollectionChanged on the new collection
coll.CollectionChanged += action;
}
}
Надеюсь, это кому-то поможет.
Ответ 3
Если у вас есть свойство зависимости типа коллекции, помните следующее:
Если ваше свойство является ссылочным типом, значение по умолчанию, указанное в метаданных свойства зависимостей, не является значением по умолчанию для экземпляра; вместо этого это значение по умолчанию применяется ко всем экземплярам типа. [...]
Чтобы исправить эту проблему, вы должны reset значение свойства зависимостей коллекции к уникальному экземпляру как часть вызова конструктора класса.
(см. MSDN Свойства зависимости типа коллекции)
Чтобы ответить на вопрос Сэма (я просто столкнулся с той же проблемой):
Сделайте свой CollectionChanged-обработчик нестационарным и отмените подписку/повторно подписаться на уровне экземпляра.
private static void OnSpecialDaysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var calendar = d as RadCalendar;
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged)e.OldValue;
// Unsubscribe from CollectionChanged on the old collection of the DP-instance (!)
coll.CollectionChanged -= d.SpecialDays_CollectionChanged;
}
if (e.NewValue != null)
{
var coll = (ObservableCollection<DateTime>)e.NewValue;
calendar.DayTemplateSelector = new SpecialDaySelector(coll, GetSpecialDayTemplate(d));
// Subscribe to CollectionChanged on the new collection of the DP-instance (!)
coll.CollectionChanged += d.SpecialDays_CollectionChanged;
}
}
private void SpecialDays_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// handle CollectionChanged on instance-level
}