删除集合中的项目时,ObservableCollection依赖项属性不会更新

时间:2010-12-06 00:42:37

标签: wpf dependency-properties observablecollection

我在控件上有一个ObservableCollection类型的附加属性。如果我在集合中添加或删除项目,则ui不会更新。但是,如果我用一个新的替换集合,那么ui会更新ViewModel。

有人能给我一个我在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));
}
}

我知道我需要注册该集合已更改,但我不确定如何在依赖属性中执行此操作

3 个答案:

答案 0 :(得分:36)

集合中的更改不会触发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
}

答案 1 :(得分:5)

这只是为了补充托马斯的答案。在我的代码中,我通过创建一个类似于下面的处理程序对象来与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's 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;
    }
}

希望这对某人有帮助。

答案 2 :(得分:3)

如果您有一个集合类型依赖项属性,请记住以下几点:

  

如果您的属性是引用类型,则依赖项属性元数据中指定的默认值不是每个实例的默认值;相反,它是一个默认值,适用于该类型的所有实例。 [...]
  要解决此问题,必须将集合依赖项属性值重置为唯一实例,作为类构造函数调用的一部分。

(请参阅MSDN Collection-Type Dependency Properties

回答Sam的问题(我遇到了同样的问题):

使您的CollectionChanged-handler非静态,并在实例级别取消订阅/重新订阅。

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 -= calendar.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 += calendar.SpecialDays_CollectionChanged;
  }
}

private void SpecialDays_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // handle CollectionChanged on instance-level
}