namespace AntDesignWPF.Controls { using System; using System.ComponentModel; using System.Windows; using System.Windows.Data; /// ///依赖属性描述符的 AddValueChanged 会导致内存泄漏,如您所知。 ///因此,如此处所述,您可以创建自定义类 PropertyChangeNotifier 来监听 ///到任何依赖属性更改。 ///此类利用绑定使用弱引用来管理关联的事实 ///因此,该类不会对属性更改它的对象进行 root 权限。它还使用一个 WeakReference ///以维护对它正在监视其属性的对象的引用,而无需对该对象进行 root 设置。 ///通过这种方式,您可以维护这些对象的集合,以便可以取消挂钩属性 ///稍后更改,而不必担心该集合会对您正在监视其值的对象进行 root。 ///完整的实现可以在这里找到:http://agsmith.wordpress.com/2008/04/07/propertydescriptor-addvaluechanged-alternative/ /// internal sealed class PropertyChangeNotifier : DependencyObject, IDisposable { private WeakReference _propertySource; public PropertyChangeNotifier(DependencyObject propertySource, string path) : this(propertySource, new PropertyPath(path)) { } public PropertyChangeNotifier(DependencyObject propertySource, DependencyProperty property) : this(propertySource, new PropertyPath(property)) { } public PropertyChangeNotifier(DependencyObject propertySource, PropertyPath property) { if (null == propertySource) { throw new ArgumentNullException(nameof(propertySource)); } if (null == property) { throw new ArgumentNullException(nameof(property)); } this._propertySource = new WeakReference(propertySource); var binding = new Binding(); binding.Path = property; binding.Mode = BindingMode.OneWay; binding.Source = propertySource; BindingOperations.SetBinding(this, ValueProperty, binding); } public DependencyObject PropertySource { get { try { // note, it is possible that accessing the target property // will result in an exception so i’ve wrapped this check // in a try catch return this._propertySource.IsAlive ? this._propertySource.Target as DependencyObject : null; } catch { return null; } } } /// /// Identifies the dependency property /// public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(PropertyChangeNotifier), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnPropertyChanged))); /// /// Returns/sets the value of the property /// /// [Description("Returns/sets the value of the property")] [Category("Behavior")] [Bindable(true)] public object Value { get { return (object)this.GetValue(ValueProperty); } set { this.SetValue(ValueProperty, value); } } private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var notifier = (PropertyChangeNotifier)d; if (notifier.RaiseValueChanged) { notifier.ValueChanged?.Invoke(notifier.PropertySource, EventArgs.Empty); } } public event EventHandler ValueChanged; public bool RaiseValueChanged { get; set; } = true; public void Dispose() { BindingOperations.ClearBinding(this, ValueProperty); } } }