Browse Source

Merge branch 'master' into feature/1078-findancestor-bindings

Steven Kirk 8 years ago
parent
commit
261f5830f3

+ 1 - 1
build.cake

@@ -193,7 +193,7 @@ Task("Run-Net-Core-Unit-Tests")
 Task("Run-Unit-Tests")
     .IsDependentOn("Run-Net-Core-Unit-Tests")
     .IsDependentOn("Build")
-    .IsDependentOn("Run-Leak-Tests")
+    //.IsDependentOn("Run-Leak-Tests")
     .WithCriteria(() => !parameters.SkipTests)
     .Does(() =>
 {

+ 1 - 1
docs/tutorial/from-wpf.md

@@ -161,7 +161,7 @@ the same way that event class listeners are added](../spec/working-with-properti
 
 ## RenderTransforms and RenderTransformOrigin
 
-RenderTransformOrigins are different in WPF and Avalonia: If you apply a `RenderTransform`, keep in mind that our default value for the RenderTransformOrigin is `RelativePoint.Middle`. In WPF the default value is `RelativePoint.TopLeft` (0, 0). In controls like Viewbox (currently being developed) the same code will lead to a different rendering behavior:
+RenderTransformOrigins are different in WPF and Avalonia: If you apply a `RenderTransform`, keep in mind that our default value for the RenderTransformOrigin is `RelativePoint.Center`. In WPF the default value is `RelativePoint.TopLeft` (0, 0). In controls like Viewbox (currently being developed) the same code will lead to a different rendering behavior:
 
 In WPF:
 ![WPF](https://files.gitter.im/AvaloniaUI/Avalonia/cDrM/image.png)

+ 3 - 2
src/Avalonia.Base/Utilities/WeakObservable.cs

@@ -16,12 +16,13 @@ namespace Avalonia.Utilities
         /// Converts a .NET event conforming to the standard .NET event pattern into an observable
         /// sequence, subscribing weakly.
         /// </summary>
+        /// <typeparam name="TTarget">The type of target.</typeparam>
         /// <typeparam name="TEventArgs">The type of the event args.</typeparam>
         /// <param name="target">Object instance that exposes the event to convert.</param>
         /// <param name="eventName">Name of the event to convert.</param>
         /// <returns></returns>
-        public static IObservable<EventPattern<object, TEventArgs>> FromEventPattern<TEventArgs>(
-            object target, 
+        public static IObservable<EventPattern<object, TEventArgs>> FromEventPattern<TTarget, TEventArgs>(
+            TTarget target, 
             string eventName)
             where TEventArgs : EventArgs
         {

+ 12 - 12
src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs

@@ -17,22 +17,23 @@ namespace Avalonia.Utilities
         /// <summary>
         /// Subscribes to an event on an object using a weak subscription.
         /// </summary>
-        /// <typeparam name="T">The type of the event arguments.</typeparam>
+        /// <typeparam name="TTarget">The type of the target.</typeparam>
+        /// <typeparam name="TEventArgs">The type of the event arguments.</typeparam>
         /// <param name="target">The event source.</param>
         /// <param name="eventName">The name of the event.</param>
         /// <param name="subscriber">The subscriber.</param>
-        public static void Subscribe<T>(object target, string eventName, IWeakSubscriber<T> subscriber)
-            where T : EventArgs
+        public static void Subscribe<TTarget, TEventArgs>(TTarget target, string eventName, IWeakSubscriber<TEventArgs> subscriber)
+            where TEventArgs : EventArgs
         {
-            var dic = SubscriptionTypeStorage<T>.Subscribers.GetOrCreateValue(target);
-            Subscription<T> sub;
+            var dic = SubscriptionTypeStorage<TEventArgs>.Subscribers.GetOrCreateValue(target);
+            Subscription<TEventArgs> sub;
 
             if (!dic.TryGetValue(eventName, out sub))
             {
-                dic[eventName] = sub = new Subscription<T>(dic, target, eventName);
+                dic[eventName] = sub = new Subscription<TEventArgs>(dic, typeof(TTarget), target, eventName);
             }
 
-            sub.Add(new WeakReference<IWeakSubscriber<T>>(subscriber));
+            sub.Add(new WeakReference<IWeakSubscriber<TEventArgs>>(subscriber));
         }
 
         /// <summary>
@@ -84,19 +85,18 @@ namespace Avalonia.Utilities
             private WeakReference<IWeakSubscriber<T>>[] _data = new WeakReference<IWeakSubscriber<T>>[16];
             private int _count = 0;
 
-            public Subscription(SubscriptionDic<T> sdic, object target, string eventName)
+            public Subscription(SubscriptionDic<T> sdic, Type targetType, object target, string eventName)
             {
                 _sdic = sdic;
                 _target = target;
                 _eventName = eventName;
-                var t = target.GetType();
                 Dictionary<string, EventInfo> evDic;
-                if (!Accessors.TryGetValue(t, out evDic))
-                    Accessors[t] = evDic = new Dictionary<string, EventInfo>();
+                if (!Accessors.TryGetValue(targetType, out evDic))
+                    Accessors[targetType] = evDic = new Dictionary<string, EventInfo>();
 
                 if (!evDic.TryGetValue(eventName, out _info))
                 {
-                    var ev = t.GetRuntimeEvents().FirstOrDefault(x => x.Name == eventName);
+                    var ev = targetType.GetRuntimeEvents().FirstOrDefault(x => x.Name == eventName);
 
                     if (ev == null)
                     {

+ 4 - 4
src/Markup/Avalonia.Markup/Data/IndexerNode.cs

@@ -33,8 +33,8 @@ namespace Avalonia.Markup.Data
 
             if (incc != null)
             {
-                inputs.Add(WeakObservable.FromEventPattern<NotifyCollectionChangedEventArgs>(
-                    target,
+                inputs.Add(WeakObservable.FromEventPattern<INotifyCollectionChanged, NotifyCollectionChangedEventArgs>(
+                    incc,
                     nameof(incc.CollectionChanged))
                     .Where(x => ShouldUpdate(x.Sender, x.EventArgs))
                     .Select(_ => GetValue(target)));
@@ -42,8 +42,8 @@ namespace Avalonia.Markup.Data
 
             if (inpc != null)
             {
-                inputs.Add(WeakObservable.FromEventPattern<PropertyChangedEventArgs>(
-                    target,
+                inputs.Add(WeakObservable.FromEventPattern<INotifyPropertyChanged, PropertyChangedEventArgs>(
+                    inpc,
                     nameof(inpc.PropertyChanged))
                     .Where(x => ShouldUpdate(x.Sender, x.EventArgs))
                     .Select(_ => GetValue(target)));

+ 9 - 1
src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs

@@ -13,7 +13,15 @@ namespace Avalonia.Markup.Data.Plugins
     public class AvaloniaPropertyAccessorPlugin : IPropertyAccessorPlugin
     {
         /// <inheritdoc/>
-        public bool Match(WeakReference reference) => reference.Target is AvaloniaObject;
+        public bool Match(object obj, string propertyName)
+        {
+            if (obj is AvaloniaObject a)
+            {
+                return AvaloniaPropertyRegistry.Instance.FindRegistered(a, propertyName) != null;
+            }
+
+            return false;
+        }
 
         /// <summary>
         /// Starts monitoring the value of a property on an object.

+ 4 - 3
src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessorPlugin.cs

@@ -14,9 +14,10 @@ namespace Avalonia.Markup.Data.Plugins
         /// <summary>
         /// Checks whether this plugin can handle accessing the properties of the specified object.
         /// </summary>
-        /// <param name="reference">A weak reference to the object.</param>
-        /// <returns>True if the plugin can handle the object; otherwise false.</returns>
-        bool Match(WeakReference reference);
+        /// <param name="obj">The object.</param>
+        /// <param name="propertyName">The property name.</param>
+        /// <returns>True if the plugin can handle the property on the object; otherwise false.</returns>
+        bool Match(object obj, string propertyName);
 
         /// <summary>
         /// Starts monitoring the value of a property on an object.

+ 3 - 3
src/Markup/Avalonia.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs

@@ -19,7 +19,7 @@ namespace Avalonia.Markup.Data.Plugins
     public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin
     {
         /// <inheritdoc/>
-        public bool Match(WeakReference reference) => true;
+        public bool Match(object obj, string propertyName) => true;
 
         /// <summary>
         /// Starts monitoring the value of a property on an object.
@@ -36,7 +36,7 @@ namespace Avalonia.Markup.Data.Plugins
             Contract.Requires<ArgumentNullException>(propertyName != null);
 
             var instance = reference.Target;
-            var p = instance.GetType().GetRuntimeProperties().FirstOrDefault(_ => _.Name == propertyName);
+            var p = instance.GetType().GetRuntimeProperties().FirstOrDefault(x => x.Name == propertyName);
 
             if (p != null)
             {
@@ -138,7 +138,7 @@ namespace Avalonia.Markup.Data.Plugins
 
                 if (inpc != null)
                 {
-                    WeakSubscriptionManager.Subscribe<PropertyChangedEventArgs>(
+                    WeakSubscriptionManager.Subscribe(
                         inpc,
                         nameof(inpc.PropertyChanged),
                         this);

+ 1 - 1
src/Markup/Avalonia.Markup/Data/PropertyAccessorNode.cs

@@ -37,7 +37,7 @@ namespace Avalonia.Markup.Data
 
         protected override IObservable<object> StartListeningCore(WeakReference reference)
         {
-            var plugin = ExpressionObserver.PropertyAccessors.FirstOrDefault(x => x.Match(reference));
+            var plugin = ExpressionObserver.PropertyAccessors.FirstOrDefault(x => x.Match(reference.Target, PropertyName));
             var accessor = plugin?.Start(reference, PropertyName);
 
             if (_enableValidation && Next == null)

+ 12 - 0
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_AvaloniaProperty.cs

@@ -30,6 +30,16 @@ namespace Avalonia.Markup.UnitTests.Data
             Assert.Null(((IAvaloniaObjectDebug)data).GetPropertyChangedSubscribers());
         }
 
+        [Fact]
+        public async Task Should_Get_Simple_ClrProperty_Value()
+        {
+            var data = new Class1();
+            var target = new ExpressionObserver(data, "ClrProperty");
+            var result = await target.Take(1);
+
+            Assert.Equal("clr-property", result);
+        }
+
         [Fact]
         public void Should_Track_Simple_Property_Value()
         {
@@ -69,6 +79,8 @@ namespace Avalonia.Markup.UnitTests.Data
         {
             public static readonly StyledProperty<string> FooProperty =
                 AvaloniaProperty.Register<Class1, string>("Foo", defaultValue: "foo");
+
+            public string ClrProperty { get; } = "clr-property";
         }
     }
 }