종속성 속성 변경 듣기
의 변화를 들을 수 있는 방법이 있나요?DependencyProperty
값이 변경되면 알림을 받고 몇 가지 작업을 수행하려고 하는데 바인딩을 사용할 수 없습니다.그것은 이다.DependencyProperty
다른 반의
이 방법은 여기서 찾을 수 없습니다.
DependencyPropertyDescriptor
.FromProperty(RadioButton.IsCheckedProperty, typeof(RadioButton))
.AddValueChanged(radioButton, (s,e) => { /* ... */ });
주의:왜냐면DependencyPropertyDescriptor
는 어플리케이션 내의 모든 핸들러의 스태틱리스트를 가지고 있습니다.해당 핸들러가 최종적으로 삭제되지 않으면 이들 핸들러에서 참조되는 모든 오브젝트가 누수됩니다.(인스턴스 오브젝트의 일반적인 이벤트와 같이 동작하지 않습니다).
항상 다음을 사용하여 핸들러를 다시 제거합니다.descriptor.RemoveValueChanged(...)
.
의 경우DependencyProperty
가장 쉬운 방법은 값을 바인딩하고 해당 값의 변경을 듣는 것입니다.
DP가 자신의 클래스로 실장되어 있는 경우 PropertyChangedCallback을 등록하여DependencyProperty
. 이를 사용하여 속성 변경을 청취할 수 있습니다.
하위 클래스를 사용하는 경우 OverrideMetadata를 사용하여 자체 클래스를 추가할 수 있습니다.PropertyChangedCallback
원래 DP가 아닌 DP가 호출될 것입니다.
이 유틸리티 클래스를 작성했습니다.
- Dependency Property Changed Event Args에 오래된 값과 새로운 값을 지정합니다.
- 소스가 바인딩의 약한 참조에 저장됩니다.
- Binding & Binding Expression을 공개하는 것이 좋은 생각인지는 잘 모르겠습니다.
- 누수가 없다.
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);
}
}
수신하려는 컨트롤을 상속한 후 다음 항목에 직접 액세스할 수 있습니다.
protected void OnPropertyChanged(string name)
메모리 누수의 위험은 없다.
표준 OO 기술을 두려워하지 마세요.
이를 실현하는 방법은 여러 가지가 있습니다.다음은 종속 속성을 관찰 가능한 속성으로 변환하여 시스템을 사용할 수 있도록 하는 방법입니다.반응:
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);
}
}
만약 그렇다면, 한 방이면 됩니다.Static 클래스를 도입할 수 있습니다.DependencyProperty
송신원클래스도 그 dp에 바인드 되어 행선지 클래스도 DP에 바인드 됩니다.
언급URL : https://stackoverflow.com/questions/4764916/listen-to-changes-of-dependency-property
'IT' 카테고리의 다른 글
MVVM에서 모델의 역할 (0) | 2023.04.13 |
---|---|
컴파일러 오류:사용자 정의 유형이 정의되지 않았습니다. (0) | 2023.04.13 |
wpf 응용 프로그램에 이상한 블랙박스가 표시됨 (0) | 2023.04.13 |
링크 업데이트 경고를 억제하는 방법 (0) | 2023.04.13 |
c#을 사용하여 SQL Server 테이블 변경을 감시하는 방법 (0) | 2023.04.13 |