123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- using System.Collections.Generic;
- using System.ComponentModel;
- using JetBrains.Annotations;
- using UnityEngine;
- namespace SRF.Helpers
- {
- using System;
- using System.Linq;
- using System.Reflection;
- public delegate void PropertyValueChangedHandler(PropertyReference property);
- public sealed class PropertyReference
- {
- public event PropertyValueChangedHandler ValueChanged
- {
- add
- {
- if (_valueChangedListeners == null)
- {
- _valueChangedListeners = new List<PropertyValueChangedHandler>();
- }
- _valueChangedListeners.Add(value);
- if (_valueChangedListeners.Count == 1 && _target is INotifyPropertyChanged)
- {
- // Subscribe to value changed event on target.
- ((INotifyPropertyChanged)_target).PropertyChanged += OnTargetPropertyChanged;
- }
- }
- remove
- {
- if (_valueChangedListeners == null)
- {
- return;
- }
- if (_valueChangedListeners.Remove(value) && _valueChangedListeners.Count == 0 &&
- _target is INotifyPropertyChanged)
- {
- // Unsubscribe from value changed event on target.
- ((INotifyPropertyChanged) _target).PropertyChanged -= OnTargetPropertyChanged;
- }
- }
- }
- [CanBeNull] private readonly PropertyInfo _property;
- [CanBeNull] private readonly object _target;
- [CanBeNull] private readonly Attribute[] _attributes;
- [CanBeNull] private readonly Func<object> _getter;
- [CanBeNull] private readonly Action<object> _setter;
- [CanBeNull] private List<PropertyValueChangedHandler> _valueChangedListeners;
- public static PropertyReference FromLambda<T>(Func<T> getter, Action<T> setter = null, params Attribute[] attributes)
- {
- Action<object> internalSetter = null;
- if (setter != null)
- {
- internalSetter = o => setter((T)o);
- }
- return new PropertyReference(typeof(T), () => getter(), internalSetter, attributes);
- }
- /// <summary>
- /// Create a property reference from an object target and reflection PropertyInfo.
- /// This represents a property on an object.
- /// </summary>
- public PropertyReference(object target, PropertyInfo property)
- {
- SRDebugUtil.AssertNotNull(target);
- SRDebugUtil.AssertNotNull(property);
- PropertyType = property.PropertyType;
- _property = property;
- _target = target;
- #if NETFX_CORE
- if(_property.GetMethod != null && _property.GetMethod.IsPublic)
- #else
- if (property.GetGetMethod() != null)
- #endif
- {
- _getter = () => SRReflection.GetPropertyValue(target, property);
- }
- #if NETFX_CORE
- if(_property.SetMethod != null && _property.SetMethod.IsPublic)
- #else
- if (property.GetSetMethod() != null)
- #endif
- {
- _setter = (v) => SRReflection.SetPropertyValue(target, property, v);
- }
- }
-
- /// <summary>
- /// Create a property reference from lambdas. This has no underlying reflection or object associated with it.
- /// </summary>
- public PropertyReference(Type type, Func<object> getter = null, Action<object> setter = null, Attribute[] attributes = null)
- {
- SRDebugUtil.AssertNotNull(type);
- PropertyType = type;
- _attributes = attributes;
- _getter = getter;
- _setter = setter;
- }
- public Type PropertyType { get; private set; }
- public bool CanRead
- {
- get
- {
- return _getter != null;
- }
- }
- public bool CanWrite
- {
- get
- {
- return _setter != null;
- }
- }
- /// <summary>
- /// Notify any listeners to <see cref="ValueChanged"/> that the value has been updated.
- /// </summary>
- public void NotifyValueChanged()
- {
- if (_valueChangedListeners == null)
- {
- return;
- }
- foreach (var handler in _valueChangedListeners)
- {
- handler(this);
- }
- }
- public object GetValue()
- {
- if (_getter != null)
- {
- return _getter();
- }
- return null;
- }
- public void SetValue(object value)
- {
- if (_setter != null)
- {
- _setter(value);
- }
- else
- {
- throw new InvalidOperationException("Can not write to property");
- }
- }
- public T GetAttribute<T>() where T : Attribute
- {
- if (_attributes != null)
- {
- return _attributes.FirstOrDefault(p => p is T) as T;
- }
- if (_property != null)
- {
- return _property.GetCustomAttributes(typeof(T), true).FirstOrDefault() as T;
- }
- return null;
- }
- private void OnTargetPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- if (_valueChangedListeners == null || _valueChangedListeners.Count == 0)
- {
- Debug.LogWarning("[PropertyReference] Received property value changed event when there are no listeners. Did the event not get unsubscribed correctly?");
- return;
- }
- NotifyValueChanged();
- }
- }
- }
|