mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-03-02 15:50:51 +08:00
69 lines
3.2 KiB
C#
69 lines
3.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AIStudio.Wpf.ADiagram.Commands
|
|
{
|
|
/// <summary>
|
|
/// Provide a way to observe property changes of INotifyPropertyChanged objects and invokes a
|
|
/// custom action when the PropertyChanged event is fired.
|
|
/// </summary>
|
|
internal class PropertyObserver
|
|
{
|
|
private readonly Action _action;
|
|
|
|
private PropertyObserver(System.Linq.Expressions.Expression propertyExpression, Action action)
|
|
{
|
|
_action = action;
|
|
SubscribeListeners(propertyExpression);
|
|
}
|
|
|
|
private void SubscribeListeners(System.Linq.Expressions.Expression propertyExpression)
|
|
{
|
|
var propNameStack = new Stack<PropertyInfo>();
|
|
while (propertyExpression is MemberExpression temp) // Gets the root of the property chain.
|
|
{
|
|
propertyExpression = temp.Expression;
|
|
propNameStack.Push(temp.Member as PropertyInfo); // Records the member info as property info
|
|
}
|
|
|
|
if (!(propertyExpression is ConstantExpression constantExpression))
|
|
throw new NotSupportedException("Operation not supported for the given expression type. " +
|
|
"Only MemberExpression and ConstantExpression are currently supported.");
|
|
|
|
var propObserverNodeRoot = new PropertyObserverNode(propNameStack.Pop(), _action);
|
|
PropertyObserverNode previousNode = propObserverNodeRoot;
|
|
foreach (var propName in propNameStack) // Create a node chain that corresponds to the property chain.
|
|
{
|
|
var currentNode = new PropertyObserverNode(propName, _action);
|
|
previousNode.Next = currentNode;
|
|
previousNode = currentNode;
|
|
}
|
|
|
|
object propOwnerObject = constantExpression.Value;
|
|
|
|
if (!(propOwnerObject is INotifyPropertyChanged inpcObject))
|
|
throw new InvalidOperationException("Trying to subscribe PropertyChanged listener in object that " +
|
|
$"owns '{propObserverNodeRoot.PropertyInfo.Name}' property, but the object does not implements INotifyPropertyChanged.");
|
|
|
|
propObserverNodeRoot.SubscribeListenerFor(inpcObject);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Observes a property that implements INotifyPropertyChanged, and automatically calls a custom action on
|
|
/// property changed notifications. The given expression must be in this form: "() => Prop.NestedProp.PropToObserve".
|
|
/// </summary>
|
|
/// <param name="propertyExpression">Expression representing property to be observed. Ex.: "() => Prop.NestedProp.PropToObserve".</param>
|
|
/// <param name="action">Action to be invoked when PropertyChanged event occours.</param>
|
|
internal static PropertyObserver Observes<T>(Expression<Func<T>> propertyExpression, Action action)
|
|
{
|
|
return new PropertyObserver(propertyExpression.Body, action);
|
|
}
|
|
}
|
|
}
|