Files
aistudio-wpf-diagram/AIStudio.Wpf.BaseDiagram/Commands/PropertyObserverNode.cs
2021-07-29 13:55:18 +08:00

71 lines
2.3 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.BaseDiagram.Commands
{
/// <summary>
/// Represents each node of nested properties expression and takes care of
/// subscribing/unsubscribing INotifyPropertyChanged.PropertyChanged listeners on it.
/// </summary>
internal class PropertyObserverNode
{
private readonly Action _action;
private INotifyPropertyChanged _inpcObject;
public PropertyInfo PropertyInfo { get; }
public PropertyObserverNode Next { get; set; }
public PropertyObserverNode(PropertyInfo propertyInfo, Action action)
{
PropertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo));
_action = () =>
{
action?.Invoke();
if (Next == null) return;
Next.UnsubscribeListener();
GenerateNextNode();
};
}
public void SubscribeListenerFor(INotifyPropertyChanged inpcObject)
{
_inpcObject = inpcObject;
_inpcObject.PropertyChanged += OnPropertyChanged;
if (Next != null) GenerateNextNode();
}
private void GenerateNextNode()
{
var nextProperty = PropertyInfo.GetValue(_inpcObject);
if (nextProperty == null) return;
if (!(nextProperty is INotifyPropertyChanged nextInpcObject))
throw new InvalidOperationException("Trying to subscribe PropertyChanged listener in object that " +
$"owns '{Next.PropertyInfo.Name}' property, but the object does not implements INotifyPropertyChanged.");
Next.SubscribeListenerFor(nextInpcObject);
}
private void UnsubscribeListener()
{
if (_inpcObject != null)
_inpcObject.PropertyChanged -= OnPropertyChanged;
Next?.UnsubscribeListener();
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e?.PropertyName == PropertyInfo.Name || string.IsNullOrEmpty(e?.PropertyName))
{
_action?.Invoke();
}
}
}
}