Browse Source

Added typed AvaloniaProperty<T>.Changed.

José Pedro 5 years ago
parent
commit
7782261ec3

+ 3 - 0
src/Avalonia.Base/ApiCompatBaseline.txt

@@ -0,0 +1,3 @@
+Compat issues with assembly Avalonia.Base:
+CannotAddAbstractMembers : Member 'protected System.IObservable<Avalonia.AvaloniaPropertyChangedEventArgs> Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract.
+Total Issues: 1

+ 3 - 14
src/Avalonia.Base/AvaloniaProperty.cs

@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.Reactive.Subjects;
 using Avalonia.Data;
 using Avalonia.Data.Core;
 using Avalonia.Utilities;
@@ -18,7 +17,6 @@ namespace Avalonia
         public static readonly object UnsetValue = new UnsetValueType();
 
         private static int s_nextId;
-        private readonly Subject<AvaloniaPropertyChangedEventArgs> _changed;
         private readonly PropertyMetadata _defaultMetadata;
         private readonly Dictionary<Type, PropertyMetadata> _metadata;
         private readonly Dictionary<Type, PropertyMetadata> _metadataCache = new Dictionary<Type, PropertyMetadata>();
@@ -50,7 +48,6 @@ namespace Avalonia
                 throw new ArgumentException("'name' may not contain periods.");
             }
 
-            _changed = new Subject<AvaloniaPropertyChangedEventArgs>();
             _metadata = new Dictionary<Type, PropertyMetadata>();
 
             Name = name;
@@ -77,7 +74,6 @@ namespace Avalonia
             Contract.Requires<ArgumentNullException>(source != null);
             Contract.Requires<ArgumentNullException>(ownerType != null);
 
-            _changed = source._changed;
             _metadata = new Dictionary<Type, PropertyMetadata>();
 
             Name = source.Name;
@@ -139,7 +135,7 @@ namespace Avalonia
         /// An observable that is fired when this property changes on any
         /// <see cref="AvaloniaObject"/> instance.
         /// </value>
-        public IObservable<AvaloniaPropertyChangedEventArgs> Changed => _changed;
+        public IObservable<AvaloniaPropertyChangedEventArgs> Changed => GetChanged();
 
         /// <summary>
         /// Gets a method that gets called before and after the property starts being notified on an
@@ -474,15 +470,6 @@ namespace Avalonia
         public abstract void Accept<TData>(IAvaloniaPropertyVisitor<TData> vistor, ref TData data)
             where TData : struct;
 
-        /// <summary>
-        /// Notifies the <see cref="Changed"/> observable.
-        /// </summary>
-        /// <param name="e">The observable arguments.</param>
-        internal void NotifyChanged(AvaloniaPropertyChangedEventArgs e)
-        {
-            _changed.OnNext(e);
-        }
-
         /// <summary>
         /// Routes an untyped ClearValue call to a typed call.
         /// </summary>
@@ -553,6 +540,8 @@ namespace Avalonia
             _hasMetadataOverrides = true;
         }
 
+        protected abstract IObservable<AvaloniaPropertyChangedEventArgs> GetChanged();
+
         private PropertyMetadata GetMetadataWithOverrides(Type type)
         {
             if (type is null)

+ 27 - 0
src/Avalonia.Base/AvaloniaProperty`1.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Reactive.Subjects;
 using Avalonia.Data;
 using Avalonia.Utilities;
 
@@ -10,6 +11,8 @@ namespace Avalonia
     /// <typeparam name="TValue">The value type of the property.</typeparam>
     public abstract class AvaloniaProperty<TValue> : AvaloniaProperty
     {
+        private readonly Subject<AvaloniaPropertyChangedEventArgs<TValue>> _changed;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="AvaloniaProperty{TValue}"/> class.
         /// </summary>
@@ -24,6 +27,7 @@ namespace Avalonia
             Action<IAvaloniaObject, bool> notifying = null)
             : base(name, typeof(TValue), ownerType, metadata, notifying)
         {
+            _changed = new Subject<AvaloniaPropertyChangedEventArgs<TValue>>();
         }
 
         /// <summary>
@@ -38,8 +42,31 @@ namespace Avalonia
             PropertyMetadata metadata)
             : base(source, ownerType, metadata)
         {
+            _changed = source is AvaloniaProperty<TValue> p ? p._changed : new Subject<AvaloniaPropertyChangedEventArgs<TValue>>();
         }
 
+        /// <summary>
+        /// Gets an observable that is fired when this property changes on any
+        /// <see cref="AvaloniaObject"/> instance.
+        /// </summary>
+        /// <value>
+        /// An observable that is fired when this property changes on any
+        /// <see cref="AvaloniaObject"/> instance.
+        /// </value>
+
+        public new IObservable<AvaloniaPropertyChangedEventArgs<TValue>> Changed => _changed;
+
+        /// <summary>
+        /// Notifies the <see cref="Changed"/> observable.
+        /// </summary>
+        /// <param name="e">The observable arguments.</param>
+        internal void NotifyChanged(AvaloniaPropertyChangedEventArgs<TValue> e)
+        {
+            _changed.OnNext(e);
+        }
+
+        protected override IObservable<AvaloniaPropertyChangedEventArgs> GetChanged() => Changed;
+
         protected BindingValue<object> TryConvert(object value)
         {
             if (value == UnsetValue)

+ 2 - 2
src/Avalonia.Controls/Mixins/SelectableMixin.cs

@@ -42,7 +42,7 @@ namespace Avalonia.Controls.Mixins
         {
             Contract.Requires<ArgumentNullException>(isSelected != null);
 
-            isSelected.Changed.Subscribe(x =>
+            isSelected.Changed.Subscribe((AvaloniaPropertyChangedEventArgs x) =>
             {
                 var sender = x.Sender as TControl;
 
@@ -58,4 +58,4 @@ namespace Avalonia.Controls.Mixins
             });
         }
     }
-}
+}

+ 1 - 1
src/Avalonia.Controls/NativeMenu.Export.cs

@@ -73,7 +73,7 @@ namespace Avalonia.Controls
                     throw new InvalidOperationException("IsNativeMenuExported property is read-only");
                 info.ChangingIsExported = false;
             });
-            MenuProperty.Changed.Subscribe(args =>
+            MenuProperty.Changed.Subscribe((AvaloniaPropertyChangedEventArgs args) =>
             {
                 if (args.Sender is TopLevel tl)
                 {

+ 1 - 1
src/Avalonia.Controls/NativeMenuItem.cs

@@ -20,7 +20,7 @@ namespace Avalonia.Controls
 
         static NativeMenuItem()
         {
-            MenuProperty.Changed.Subscribe(args =>
+            MenuProperty.Changed.Subscribe((AvaloniaPropertyChangedEventArgs args) =>
             {
                 var item = (NativeMenuItem)args.Sender;
                 var value = (NativeMenu)args.NewValue;

+ 1 - 1
src/Avalonia.Controls/Presenters/TextPresenter.cs

@@ -82,7 +82,7 @@ namespace Avalonia.Controls.Presenters
                 TextAlignmentProperty, TextWrappingProperty, TextBlock.FontSizeProperty,
                 TextBlock.FontStyleProperty, TextBlock.FontWeightProperty, TextBlock.FontFamilyProperty);
 
-            Observable.Merge(TextProperty.Changed, TextBlock.ForegroundProperty.Changed,
+            Observable.Merge<AvaloniaPropertyChangedEventArgs>(TextProperty.Changed, TextBlock.ForegroundProperty.Changed,
                 TextAlignmentProperty.Changed, TextWrappingProperty.Changed,
                 TextBlock.FontSizeProperty.Changed, TextBlock.FontStyleProperty.Changed, 
                 TextBlock.FontWeightProperty.Changed, TextBlock.FontFamilyProperty.Changed,

+ 1 - 1
src/Avalonia.Controls/TextBlock.cs

@@ -138,7 +138,7 @@ namespace Avalonia.Controls
                 FontStyleProperty, TextWrappingProperty, FontFamilyProperty,
                 TextTrimmingProperty, TextProperty, PaddingProperty, LineHeightProperty, MaxLinesProperty);
 
-            Observable.Merge(TextProperty.Changed, ForegroundProperty.Changed,
+            Observable.Merge<AvaloniaPropertyChangedEventArgs>(TextProperty.Changed, ForegroundProperty.Changed,
                 TextAlignmentProperty.Changed, TextWrappingProperty.Changed,
                 TextTrimmingProperty.Changed, FontSizeProperty.Changed,
                 FontStyleProperty.Changed, FontWeightProperty.Changed,

+ 1 - 1
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs

@@ -92,7 +92,7 @@ namespace Avalonia.Base.UnitTests
             var target = new Class1();
             bool raised = false;
 
-            Class1.FooProperty.Changed.Subscribe(e =>
+            Class1.FooProperty.Changed.Subscribe((AvaloniaPropertyChangedEventArgs e) =>
                 raised = e.Property == Class1.FooProperty &&
                          (string)e.OldValue == "initial" &&
                          (string)e.NewValue == "newvalue" &&

+ 2 - 2
tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs

@@ -83,7 +83,7 @@ namespace Avalonia.Base.UnitTests
             var target = new Class1();
             string value = null;
 
-            Class1.FooProperty.Changed.Subscribe(x => value = (string)x.NewValue);
+            Class1.FooProperty.Changed.Subscribe((AvaloniaPropertyChangedEventArgs x) => value = (string)x.NewValue);
             target.SetValue(Class1.FooProperty, "newvalue");
 
             Assert.Equal("newvalue", value);
@@ -95,7 +95,7 @@ namespace Avalonia.Base.UnitTests
             var target = new Class1();
             var result = new List<string>();
 
-            Class1.FooProperty.Changed.Subscribe(x => result.Add((string)x.NewValue));
+            Class1.FooProperty.Changed.Subscribe((AvaloniaPropertyChangedEventArgs x) => result.Add((string)x.NewValue));
             target.SetValue(Class1.FooProperty, "animated", BindingPriority.Animation);
             target.SetValue(Class1.FooProperty, "local");