Is there any way to listen to changes of a DependencyProperty
? I want to be notified and perform some actions when the value changes but I cannot use binding. It is a DependencyProperty
of another class.
A dependency property is a specific type of property where the value is followed by a keen property system which is also a part of the Windows Runtime App. A class which defines a dependency property must be inherited from the DependencyObject class.
Arguably the biggest feature of a dependency property is its built-in ability to provide change notification. The motivation for adding such intelligence to properties is to enable rich functionality directly from declarative markup.
The purpose of dependency properties is to provide a way to compute the value of a property based on the value of other inputs, such as: System properties, such as themes and user preference. Just-in-time property determination mechanisms, such as data binding and animations/storyboards.
A DependencyProperty maintains a static reference of all the DependencyProperty you register in WPF object hierarchy. It maintains a HashTable named PropertyFromName which it uses internally to get the DependencyProperty object. So in other word, each dependencyProperty object is registered in a global HashTable.
This method is definitely missing here:
DependencyPropertyDescriptor .FromProperty(RadioButton.IsCheckedProperty, typeof(RadioButton)) .AddValueChanged(radioButton, (s,e) => { /* ... */ });
If it's a DependencyProperty
of a separate class, the easiest way is to bind a value to it, and listen to changes on that value.
If the DP is one you're implementing in your own class, then you can register a PropertyChangedCallback when you create the DependencyProperty
. You can use this to listen to changes of the property.
If you're working with a subclass, you can use OverrideMetadata to add your own PropertyChangedCallback
to the DP that will get called instead of any original one.
I wrote this utility class:
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With