AvaloniaPropertyAccessorPlugin.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Reactive.Linq;
  5. namespace Avalonia.Data.Core.Plugins
  6. {
  7. /// <summary>
  8. /// Reads a property from a <see cref="AvaloniaObject"/>.
  9. /// </summary>
  10. public class AvaloniaPropertyAccessorPlugin : IPropertyAccessorPlugin
  11. {
  12. /// <inheritdoc/>
  13. public bool Match(object obj, string propertyName)
  14. {
  15. if (obj is AvaloniaObject o)
  16. {
  17. return LookupProperty(o, propertyName) != null;
  18. }
  19. return false;
  20. }
  21. /// <summary>
  22. /// Starts monitoring the value of a property on an object.
  23. /// </summary>
  24. /// <param name="reference">A weak reference to the object.</param>
  25. /// <param name="propertyName">The property name.</param>
  26. /// <returns>
  27. /// An <see cref="IPropertyAccessor"/> interface through which future interactions with the
  28. /// property will be made.
  29. /// </returns>
  30. public IPropertyAccessor Start(WeakReference reference, string propertyName)
  31. {
  32. Contract.Requires<ArgumentNullException>(reference != null);
  33. Contract.Requires<ArgumentNullException>(propertyName != null);
  34. var instance = reference.Target;
  35. var o = (AvaloniaObject)instance;
  36. var p = LookupProperty(o, propertyName);
  37. if (p != null)
  38. {
  39. return new Accessor(new WeakReference<AvaloniaObject>(o), p);
  40. }
  41. else if (instance != AvaloniaProperty.UnsetValue)
  42. {
  43. var message = $"Could not find AvaloniaProperty '{propertyName}' on '{instance}'";
  44. var exception = new MissingMemberException(message);
  45. return new PropertyError(new BindingNotification(exception, BindingErrorType.Error));
  46. }
  47. else
  48. {
  49. return null;
  50. }
  51. }
  52. private static AvaloniaProperty LookupProperty(AvaloniaObject o, string propertyName)
  53. {
  54. return AvaloniaPropertyRegistry.Instance.FindRegistered(o, propertyName);
  55. }
  56. private static bool IsOfType(Type type, string typeName)
  57. {
  58. while (type != null)
  59. {
  60. if (type.Name == typeName)
  61. {
  62. return true;
  63. }
  64. type = type.BaseType;
  65. }
  66. return false;
  67. }
  68. private class Accessor : PropertyAccessorBase
  69. {
  70. private readonly WeakReference<AvaloniaObject> _reference;
  71. private readonly AvaloniaProperty _property;
  72. private IDisposable _subscription;
  73. public Accessor(WeakReference<AvaloniaObject> reference, AvaloniaProperty property)
  74. {
  75. Contract.Requires<ArgumentNullException>(reference != null);
  76. Contract.Requires<ArgumentNullException>(property != null);
  77. _reference = reference;
  78. _property = property;
  79. }
  80. public AvaloniaObject Instance
  81. {
  82. get
  83. {
  84. AvaloniaObject result;
  85. _reference.TryGetTarget(out result);
  86. return result;
  87. }
  88. }
  89. public override Type PropertyType => _property.PropertyType;
  90. public override object Value => Instance?.GetValue(_property);
  91. public override bool SetValue(object value, BindingPriority priority)
  92. {
  93. if (!_property.IsReadOnly)
  94. {
  95. Instance.SetValue(_property, value, priority);
  96. return true;
  97. }
  98. return false;
  99. }
  100. protected override void SubscribeCore()
  101. {
  102. _subscription = Instance?.GetObservable(_property).Subscribe(PublishValue);
  103. }
  104. protected override void UnsubscribeCore()
  105. {
  106. _subscription?.Dispose();
  107. _subscription = null;
  108. }
  109. }
  110. }
  111. }