听取依赖属性的变化

有没有办法听取DependencyProperty变化? 我希望得到通知,并在值发生变化时执行一些操作,但不能使用绑定。 它是另一个类的一个DependencyProperty

如果它是一个单独的类的DependencyProperty ,最简单的方法是绑定一个值,并听取对该值的更改。

如果DP是您在自己的类中实现的DP,则可以在创buildDependencyProperty时注册PropertyChangedCallback 。 您可以使用此来聆听属性的更改。

如果您正在使用子类,则可以使用OverrideMetadata将您自己的PropertyChangedCallback添加到将被调用的DP,而不是原来的调用。

这个方法在这里肯定是缺less的:

 DependencyPropertyDescriptor .FromProperty(RadioButton.IsCheckedProperty, typeof(RadioButton)) .AddValueChanged(radioButton, (s,e) => { /* ... */ }); 

我写了这个工具类:

  • 它给了DependencyPropertyChangedEventArgs新旧值。
  • 源被存储在绑定中的弱引用中。
  • 不知道是否暴露Binding和BindingExpression是一个好主意。
  • 没有泄漏。
 using System; using System.Collections.Concurrent; using System.Windows; using System.Windows.Data; public sealed class DependencyPropertyListener : DependencyObject, IDisposable { private static readonly ConcurrentDictionary<DependencyProperty, PropertyPath> Cache = new ConcurrentDictionary<DependencyProperty, PropertyPath>(); private static readonly DependencyProperty ProxyProperty = DependencyProperty.Register( "Proxy", typeof(object), typeof(DependencyPropertyListener), new PropertyMetadata(null, OnSourceChanged)); private readonly Action<DependencyPropertyChangedEventArgs> onChanged; private bool disposed; public DependencyPropertyListener( DependencyObject source, DependencyProperty property, Action<DependencyPropertyChangedEventArgs> onChanged = null) : this(source, Cache.GetOrAdd(property, x => new PropertyPath(x)), onChanged) { } public DependencyPropertyListener( DependencyObject source, PropertyPath property, Action<DependencyPropertyChangedEventArgs> onChanged) { this.Binding = new Binding { Source = source, Path = property, Mode = BindingMode.OneWay, }; this.BindingExpression = (BindingExpression)BindingOperations.SetBinding(this, ProxyProperty, this.Binding); this.onChanged = onChanged; } public event EventHandler<DependencyPropertyChangedEventArgs> Changed; public BindingExpression BindingExpression { get; } public Binding Binding { get; } public DependencyObject Source => (DependencyObject)this.Binding.Source; public void Dispose() { if (this.disposed) { return; } this.disposed = true; BindingOperations.ClearBinding(this, ProxyProperty); } private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var listener = (DependencyPropertyListener)d; if (listener.disposed) { return; } listener.onChanged?.Invoke(e); listener.OnChanged(e); } private void OnChanged(DependencyPropertyChangedEventArgs e) { this.Changed?.Invoke(this, e); } } 

 using System; using System.Windows; public static class Observe { public static IDisposable PropertyChanged( this DependencyObject source, DependencyProperty property, Action<DependencyPropertyChangedEventArgs> onChanged = null) { return new DependencyPropertyListener(source, property, onChanged); } } 

有多种方式来归档这个。 这是一种将依赖属性转换为可观察对象的方法,以便可以使用System.Reactive进行订阅:

 public static class DependencyObjectExtensions { public static IObservable<EventArgs> Observe<T>(this T component, DependencyProperty dependencyProperty) where T:DependencyObject { return Observable.Create<EventArgs>(observer => { EventHandler update = (sender, args) => observer.OnNext(args); var property = DependencyPropertyDescriptor.FromProperty(dependencyProperty, typeof(T)); property.AddValueChanged(component, update); return Disposable.Create(() => property.RemoveValueChanged(component, update)); }); } } 

用法

请记住处理订阅以防止内存泄漏:

 public partial sealed class MyControl : UserControl, IDisposable { public MyControl() { InitializeComponent(); // this is the interesting part var subscription = this.Observe(MyProperty) .Subscribe(args => { /* ... */})); // the rest of the class is infrastructure for proper disposing Subscriptions.Add(subscription); Dispatcher.ShutdownStarted += DispatcherOnShutdownStarted; } private IList<IDisposable> Subscriptions { get; } = new List<IDisposable>(); private void DispatcherOnShutdownStarted(object sender, EventArgs eventArgs) { Dispose(); } Dispose(){ Dispose(true); } ~MyClass(){ Dispose(false); } bool _isDisposed; void Dispose(bool isDisposing) { if(_disposed) return; foreach(var subscription in Subscriptions) { subscription?.Dispose(); } _isDisposed = true; if(isDisposing) GC.SupressFinalize(this); } } 

如果是这样,一个黑客。 你可以用一个DependencyProperty来引入一个Static类。 你的源类也绑定到该DP,你的目标类也绑定到DP。

你可以inheritance你试图监听的控制,然后直接访问:

 protected void OnPropertyChanged(string name) 

没有内存泄漏的风险。

不要害怕标准的面向对象技术。