Подтвердить что ты не робот

Свойство зависимостей 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));
}
}

Я понимаю, что мне нужно зарегистрировать, что коллекция изменилась, но я не уверен, как это сделать в свойстве зависимости

4b9b3361

Ответ 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
}