【问题标题】:Is my attached DependencyProperty leaking when subscribing to a long-lived object event?订阅长寿命对象事件时,我附加的 DependencyProperty 是否泄漏?
【发布时间】:2012-12-22 05:52:23
【问题描述】:

我一直在编写一个小的 Silverlight 帮助类来实现一个附加属性,该属性可以绑定到 ICollection / INotifyCollectionChanged 并在绑定集合为空时切换目标对象的可见性。

我没有完全掌握 DependencyProperty 关于内存管理和对象生命周期的行为。

这是源代码:

public class DisplayOnCollectionEmpty : DependencyObject
{
    #region Constructor and Static Constructor

    /// <summary>
    /// This is not a constructable class, but it cannot be static because 
    /// it derives from DependencyObject.
    /// </summary>
    private DisplayOnCollectionEmpty()
    {
    }

    #endregion

    public static object GetCollection(DependencyObject obj)
    {
        return (object)obj.GetValue(CollectionProperty);
    }

    public static void SetCollection(DependencyObject obj, object value)
    {
        obj.SetValue(CollectionProperty, value);
    }

    // Using a DependencyProperty as the backing store for Collection.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CollectionProperty =
    DependencyProperty.RegisterAttached("Collection", typeof(object), typeof(FrameworkElement), new PropertyMetadata(OnCollectionPropertyChanged));

    private static void OnCollectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement fe = d as FrameworkElement;

        NotifyCollectionChangedEventHandler onCollectionChanged = (sender, collectionChangedEventArgs) =>
        {
            fe.Visibility = GetVisibility(e.NewValue as ICollection);
        };

        if (e.OldValue is INotifyCollectionChanged)
        {
            ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= onCollectionChanged;
        }
        if (e.NewValue is INotifyCollectionChanged)
        {
            ((INotifyCollectionChanged)e.NewValue).CollectionChanged += onCollectionChanged;
        }

        fe.Visibility = GetVisibility(e.NewValue as ICollection);
    }

    private static Visibility GetVisibility(ICollection collection)
    {
        if (collection == null) return Visibility.Visible;
        return collection.Count < 1 ? Visibility.Visible : Visibility.Collapsed;
    }
}

【问题讨论】:

  • 几点注意事项: 1. 声明附加属性的类不需要派生自DependencyObject。因此不需要私有构造函数。 2.RegisterAttached中的ownerType(3rd)参数必须是声明类,这里是DisplayOnCollectionEmpty,不是FrameworkElement。
  • 为什么不直接将 FrameworkElement 的 Visibility 绑定到 Collection 并使用适当的 binding converter
  • @Clemens :我不使用 IValueConverter 因为我还想在更新集合时更改值,AFAIK 我不能用 IValueConverter 做到这一点,因为它不公开目标 DependencyObject 或 DependencyProperty .感谢您在第一篇文章中的帮助。所以没有办法指定我希望我的附加属性仅适用于特定类型(此处为 FrameworkElement)?
  • 啊,我应该看到的。您可以通过在 GetCollection 和 SetCollection 中使用 FrameworkElement 作为参数类型,而不是 DependencyObject 来指定该属性只能应用于 FrameworkElement。

标签: c# silverlight xaml dependency-properties windows-phone


【解决方案1】:

您似乎在设置集合时订阅了 INotifyCollectionChanged 的​​ CollectionChanged,并且仅在更改时才取消订阅。

我还将通过从 CollectionChanged 事件中注销来处理 FrameworkElement 的 Unloaded 事件。

我看到你没有检查 e.OldValue 或 e.NewValue 是否为空。

为了同样的目的,您可以使用行为来代替依赖属性。我的想法主要是一样的。我还没有考虑过利弊。 以下是一些关于行为与依赖属性的有趣链接: Interactivity.Behavior<T> vs attached properties

https://web.archive.org/web/20130622113553/http://briannoyes.net/2012/12/20/AttachedBehaviorsVsAttachedPropertiesVsBlendBehaviors.aspx

【讨论】:

  • 卸载时的清理有时可能是不可靠的,因为控件可以被卸载然后再次加载,具体取决于各种因素,例如其父控件在其可见性更改时的行为等。这可能会离开绑定的附加属性完好无损,但由于事件处理程序已断开连接,附加属性不再有任何效果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-29
  • 2012-11-11
  • 1970-01-01
  • 2016-04-17
  • 1970-01-01
相关资源
最近更新 更多