2025-07-31 20:12:24 +08:00
|
|
|
|
namespace AntDesignWPF.Controls
|
2025-07-11 09:20:23 +08:00
|
|
|
|
{
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Data;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-07-31 20:12:24 +08:00
|
|
|
|
///依赖属性描述符的 AddValueChanged 会导致内存泄漏,如您所知。
|
|
|
|
|
|
///因此,如此处所述,您可以创建自定义类 PropertyChangeNotifier 来监听
|
|
|
|
|
|
///到任何依赖属性更改。
|
|
|
|
|
|
///此类利用绑定使用弱引用来管理关联的事实
|
|
|
|
|
|
///因此,该类不会对属性更改它的对象进行 root 权限。它还使用一个 WeakReference
|
|
|
|
|
|
///以维护对它正在监视其属性的对象的引用,而无需对该对象进行 root 设置。
|
|
|
|
|
|
///通过这种方式,您可以维护这些对象的集合,以便可以取消挂钩属性
|
|
|
|
|
|
///稍后更改,而不必担心该集合会对您正在监视其值的对象进行 root。
|
|
|
|
|
|
///完整的实现可以在这里找到:http://agsmith.wordpress.com/2008/04/07/propertydescriptor-addvaluechanged-alternative/
|
2025-07-11 09:20:23 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Identifies the <see cref="Value"/> dependency property
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static readonly DependencyProperty ValueProperty
|
|
|
|
|
|
= DependencyProperty.Register("Value", typeof(object), typeof(PropertyChangeNotifier),
|
|
|
|
|
|
new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnPropertyChanged)));
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Returns/sets the value of the property
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <seealso cref="ValueProperty"/>
|
|
|
|
|
|
[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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|