Browse Source

Added GetPropertyChangedObservable.

Replaced `GetObservableWithHistory` with `GetPropertyChangedObservable`.
Steven Kirk 8 years ago
parent
commit
3150d3f10a

+ 8 - 10
src/Avalonia.Base/AvaloniaObjectExtensions.cs

@@ -69,26 +69,24 @@ namespace Avalonia
         }
 
         /// <summary>
-        /// Gets an observable for a <see cref="AvaloniaProperty"/>.
+        /// Gets an observable that listens for property changed events for an
+        /// <see cref="AvaloniaProperty"/>.
         /// </summary>
         /// <param name="o">The object.</param>
-        /// <typeparam name="T">The type of the property.</typeparam>
         /// <param name="property">The property.</param>
         /// <returns>
-        /// An observable which when subscribed pushes the old and new values of the property each
-        /// time it is changed. Note that the observable returned from this method does not fire
-        /// with the current value of the property immediately.
+        /// An observable which when subscribed pushes the property changed event args
+        /// each time a <see cref="IAvaloniaObject.PropertyChanged"/> event is raised
+        /// for the specified property.
         /// </returns>
-        public static IObservable<Tuple<T, T>> GetObservableWithHistory<T>(
+        public static IObservable<AvaloniaPropertyChangedEventArgs> GetPropertyChangedObservable(
             this IAvaloniaObject o, 
-            AvaloniaProperty<T> property)
+            AvaloniaProperty property)
         {
             Contract.Requires<ArgumentNullException>(o != null);
             Contract.Requires<ArgumentNullException>(property != null);
 
-            return new AvaloniaPropertyObservable<T>(o, property)
-                .Buffer(2, 1)
-                .Select(x => Tuple.Create(x[0], x[1]));
+            return new AvaloniaPropertyChangedObservable(o, property);
         }
 
         /// <summary>

+ 46 - 0
src/Avalonia.Base/Reactive/AvaloniaPropertyChangedObservable.cs

@@ -0,0 +1,46 @@
+using System;
+
+namespace Avalonia.Reactive
+{
+    internal class AvaloniaPropertyChangedObservable : 
+        LightweightObservableBase<AvaloniaPropertyChangedEventArgs>,
+        IDescription
+    {
+        private readonly WeakReference<IAvaloniaObject> _target;
+        private readonly AvaloniaProperty _property;
+
+        public AvaloniaPropertyChangedObservable(
+            IAvaloniaObject target,
+            AvaloniaProperty property)
+        {
+            _target = new WeakReference<IAvaloniaObject>(target);
+            _property = property;
+        }
+
+        public string Description => $"{_target.GetType().Name}.{_property.Name}";
+
+        protected override void Initialize()
+        {
+            if (_target.TryGetTarget(out var target))
+            {
+                target.PropertyChanged += PropertyChanged;
+            }
+        }
+
+        protected override void Deinitialize()
+        {
+            if (_target.TryGetTarget(out var target))
+            {
+                target.PropertyChanged -= PropertyChanged;
+            }
+        }
+
+        private void PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
+        {
+            if (e.Property == _property)
+            {
+                PublishNext(e);
+            }
+        }
+    }
+}

+ 1 - 2
src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs

@@ -1,9 +1,8 @@
 using System;
-using Avalonia.Utilities;
 
 namespace Avalonia.Reactive
 {
-    public class AvaloniaPropertyObservable<T> : LightweightObservableBase<T>, IDescription
+    internal class AvaloniaPropertyObservable<T> : LightweightObservableBase<T>, IDescription
     {
         private readonly WeakReference<IAvaloniaObject> _target;
         private readonly AvaloniaProperty _property;

+ 14 - 26
src/Avalonia.Controls/Mixins/ContentControlMixin.cs

@@ -49,11 +49,9 @@ namespace Avalonia.Controls.Mixins
             Contract.Requires<ArgumentNullException>(content != null);
             Contract.Requires<ArgumentNullException>(logicalChildrenSelector != null);
 
-            EventHandler<RoutedEventArgs> templateApplied = (s, ev) =>
+            void TemplateApplied(object s, RoutedEventArgs ev)
             {
-                var sender = s as TControl;
-
-                if (sender != null)
+                if (s is TControl sender)
                 {
                     var e = (TemplateAppliedEventArgs)ev;
                     var presenter = (IControl)e.NameScope.Find(presenterName);
@@ -64,12 +62,12 @@ namespace Avalonia.Controls.Mixins
 
                         var logicalChildren = logicalChildrenSelector(sender);
                         var subscription = presenter
-                            .GetObservableWithHistory(ContentPresenter.ChildProperty)
-                            .Subscribe(child => UpdateLogicalChild(
+                            .GetPropertyChangedObservable(ContentPresenter.ChildProperty)
+                            .Subscribe(c => UpdateLogicalChild(
                                 sender,
-                                logicalChildren, 
-                                child.Item1, 
-                                child.Item2));
+                                logicalChildren,
+                                c.OldValue,
+                                c.NewValue));
 
                         UpdateLogicalChild(
                             sender,
@@ -80,18 +78,16 @@ namespace Avalonia.Controls.Mixins
                         subscriptions.Value.Add(sender, subscription);
                     }
                 }
-            };
+            }
 
             TemplatedControl.TemplateAppliedEvent.AddClassHandler(
                 typeof(TControl),
-                templateApplied,
+                TemplateApplied,
                 RoutingStrategies.Direct);
 
             content.Changed.Subscribe(e =>
             {
-                var sender = e.Sender as TControl;
-
-                if (sender != null)
+                if (e.Sender is TControl sender)
                 {
                     var logicalChildren = logicalChildrenSelector(sender);
                     UpdateLogicalChild(sender, logicalChildren, e.OldValue, e.NewValue);
@@ -100,9 +96,7 @@ namespace Avalonia.Controls.Mixins
 
             Control.TemplatedParentProperty.Changed.Subscribe(e =>
             {
-                var sender = e.Sender as TControl;
-
-                if (sender != null)
+                if (e.Sender is TControl sender)
                 {
                     var logicalChild = logicalChildrenSelector(sender).FirstOrDefault() as IControl;
                     logicalChild?.SetValue(Control.TemplatedParentProperty, sender.TemplatedParent);
@@ -111,13 +105,9 @@ namespace Avalonia.Controls.Mixins
 
             TemplatedControl.TemplateProperty.Changed.Subscribe(e =>
             {
-                var sender = e.Sender as TControl;
-
-                if (sender != null)
+                if (e.Sender is TControl sender)
                 {
-                    IDisposable subscription;
-
-                    if (subscriptions.Value.TryGetValue(sender, out subscription))
+                    if (subscriptions.Value.TryGetValue(sender, out IDisposable subscription))
                     {
                         subscription.Dispose();
                         subscriptions.Value.Remove(sender);
@@ -134,9 +124,7 @@ namespace Avalonia.Controls.Mixins
         {
             if (oldValue != newValue)
             {
-                var child = oldValue as IControl;
-
-                if (child != null)
+                if (oldValue is IControl child)
                 {
                     logicalChildren.Remove(child);
                 }