क्या ए के परिवर्तनों को सुनने का कोई तरीका है DependencyProperty
? जब मूल्य में बदलाव होता है तो मैं अधिसूचित होना चाहता हूं और कुछ क्रियाएं करता हूं लेकिन मैं बाध्यकारी का उपयोग नहीं कर सकता। यह DependencyProperty
दूसरे वर्ग का है।
क्या ए के परिवर्तनों को सुनने का कोई तरीका है DependencyProperty
? जब मूल्य में बदलाव होता है तो मैं अधिसूचित होना चाहता हूं और कुछ क्रियाएं करता हूं लेकिन मैं बाध्यकारी का उपयोग नहीं कर सकता। यह DependencyProperty
दूसरे वर्ग का है।
जवाबों:
यदि यह DependencyProperty
एक अलग वर्ग का है, तो सबसे आसान तरीका यह है कि किसी मान को बाँध दिया जाए, और उस मूल्य पर बदलावों को सुनें।
यदि DP वह है जिसे आप अपने स्वयं के वर्ग में लागू कर रहे हैं, तो आप जब आप एक प्रॉपर्टीचैडबैक को पंजीकृत कर सकते हैं DependencyProperty
। आप संपत्ति के परिवर्तनों को सुनने के लिए इसका उपयोग कर सकते हैं।
यदि आप एक उपवर्ग के साथ काम कर रहे हैं, तो आप डीपी को जोड़ने के लिए ओवरराइडमेटेटाटा का उपयोग कर सकते हैं PropertyChangedCallback
जो कि किसी भी मूल के बजाय कॉल किया जाएगा।
यह विधि निश्चित रूप से यहाँ गायब है:
DependencyPropertyDescriptor
.FromProperty(RadioButton.IsCheckedProperty, typeof(RadioButton))
.AddValueChanged(radioButton, (s,e) => { /* ... */ });
descriptor.RemoveValueChanged(...)
DependencyPropertyDescriptor
में आवेदन में सभी हैंडलर की स्थिर सूची है, इसलिए हैंडलर में संदर्भित प्रत्येक वस्तु लीक हो जाएगी। यह आम घटना की तरह काम नहीं करता है।
मैंने यह उपयोगिता वर्ग लिखा है:
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
। आप स्रोत वर्ग भी उस डीपी से बंध जाते हैं और आपका गंतव्य वर्ग भी डीपी से जुड़ जाता है।