// Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; using System.Reactive.Linq; namespace Avalonia.Data.Core.Plugins { /// /// Reads a property from a . /// public class AvaloniaPropertyAccessorPlugin : IPropertyAccessorPlugin { /// public bool Match(object obj, string propertyName) { if (obj is AvaloniaObject o) { return LookupProperty(o, propertyName) != null; } return false; } /// /// Starts monitoring the value of a property on an object. /// /// A weak reference to the object. /// The property name. /// /// An interface through which future interactions with the /// property will be made. /// public IPropertyAccessor Start(WeakReference reference, string propertyName) { Contract.Requires(reference != null); Contract.Requires(propertyName != null); var instance = reference.Target; var o = (AvaloniaObject)instance; var p = LookupProperty(o, propertyName); if (p != null) { return new Accessor(new WeakReference(o), p); } else if (instance != AvaloniaProperty.UnsetValue) { var message = $"Could not find AvaloniaProperty '{propertyName}' on '{instance}'"; var exception = new MissingMemberException(message); return new PropertyError(new BindingNotification(exception, BindingErrorType.Error)); } else { return null; } } private static AvaloniaProperty LookupProperty(AvaloniaObject o, string propertyName) { return AvaloniaPropertyRegistry.Instance.FindRegistered(o, propertyName); } private static bool IsOfType(Type type, string typeName) { while (type != null) { if (type.Name == typeName) { return true; } type = type.BaseType; } return false; } private class Accessor : PropertyAccessorBase { private readonly WeakReference _reference; private readonly AvaloniaProperty _property; private IDisposable _subscription; public Accessor(WeakReference reference, AvaloniaProperty property) { Contract.Requires(reference != null); Contract.Requires(property != null); _reference = reference; _property = property; } public AvaloniaObject Instance { get { AvaloniaObject result; _reference.TryGetTarget(out result); return result; } } public override Type PropertyType => _property.PropertyType; public override object Value => Instance?.GetValue(_property); public override bool SetValue(object value, BindingPriority priority) { if (!_property.IsReadOnly) { Instance.SetValue(_property, value, priority); return true; } return false; } protected override void SubscribeCore() { _subscription = Instance?.GetObservable(_property).Subscribe(PublishValue); } protected override void UnsubscribeCore() { _subscription?.Dispose(); _subscription = null; } } } }