【问题标题】:ObservableCollection dependency property does not update when item in collection is deleted删除集合中的项目时,ObservableCollection 依赖属性不会更新
【发布时间】:2011-05-20 17:20:26
【问题描述】:

我在控件上有一个 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));
}
}

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

【问题讨论】:

    标签: wpf dependency-properties observablecollection


    【解决方案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
    }
    

    【讨论】:

    • 谢谢。是否可以在 SpecialDays_CollectionChanged 中获取依赖对象的引用?
    • 哪个依赖对象?你是说 RadCalendar 吗?不容易......无论如何,我不确定这是否有意义:如果 RadCalendar 的多个实例绑定到同一个集合怎么办?
    • 我明白你的意思。我试图让 RadCalendar 不再突出显示从集合中删除的特殊日子,所以我想我可以通过创建一个新的 SpecialDaySelector 并设置 Calendar 控件的 DayTemplateSelector 来做到这一点。
    • 我宁愿使用 IList 作为底层类型而不是 ObservableCollection,因为您始终可以将 ItemsSource 绑定到不同于 ObservableCollection 的集合,例如数组或列表。
    • 我可以请您评论一下 Matumba 下面提出的解决方案的变体吗?我在我的应用程序中实现了它(经过适当调整),它似乎有效。但也许也有一个陷阱——我对 C# 和 WPF 的了解不够,无法完全看透它。以前我使用 nowaq 的方法,但它导致了错误的行为(请参阅下面的评论)。
    【解决方案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'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;
        }
    }
    

    希望这对某人有所帮助。

    【讨论】:

    • 这很有帮助,是的,我正在寻找一种方法来访问 CollectionChangedEventHandler 中的 DependencyObject,这似乎有效。我很难相信这是唯一的方法......我们做错了什么吗?我有一个 ObservableCollection DP,当项目被添加到它时(collectionchanged 事件被触发......),我需要对主控件做一些事情(比如添加子控件)。您的解决方案是我发现的唯一一个可以访问 DependencyObj 的解决方案。自从这篇文章你找到了另一种方式?
    • 您的解决方案会导致有问题的行为:假设 ObservableCollection 依赖属性首先绑定到 OC 'aoc',然后绑定到 'null',然后再绑定到 'aoc'。最后,“aoc”的“CollectionChanged”将绑定到“var action”的两个不同值(= 两个不同的闭包),因为第一个分配的闭包永远不会被删除。
    【解决方案3】:

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

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

    (见 MSDN Collection-Type Dependency Properties

    回答山姆的问题(我刚刚遇到了同样的问题):

    使您的 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 -= 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
    }
    

    【讨论】:

    • 显示错误“DependencyObject”不包含“SpecialDays_CollectionChanged”的定义。您可能是指 calendar.SpecialDays_CollectionChanged
    猜你喜欢
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    • 2013-02-07
    相关资源
    最近更新 更多