Browse Source

Merge branch 'master' into prs/layoutissue

danwalmsley 6 years ago
parent
commit
7b0d6e060a

+ 2 - 44
src/Avalonia.Base/AvaloniaObject.cs

@@ -22,27 +22,10 @@ namespace Avalonia
     /// </remarks>
     public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged
     {
-        /// <summary>
-        /// The parent object that inherited values are inherited from.
-        /// </summary>
         private IAvaloniaObject _inheritanceParent;
-
-        /// <summary>
-        /// Maintains a list of direct property binding subscriptions so that the binding source
-        /// doesn't get collected.
-        /// </summary>
         private List<DirectBindingSubscription> _directBindings;
-
-        /// <summary>
-        /// Event handler for <see cref="INotifyPropertyChanged"/> implementation.
-        /// </summary>
         private PropertyChangedEventHandler _inpcChanged;
-
-        /// <summary>
-        /// Event handler for <see cref="PropertyChanged"/> implementation.
-        /// </summary>
         private EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChanged;
-
         private ValueStore _values;
         private ValueStore Values => _values ?? (_values = new ValueStore(this));
 
@@ -52,32 +35,7 @@ namespace Avalonia
         public AvaloniaObject()
         {
             VerifyAccess();
-
-            void Notify(AvaloniaProperty property)
-            {
-                object value = property.IsDirect ?
-                    ((IDirectPropertyAccessor)property).GetValue(this) :
-                    ((IStyledPropertyAccessor)property).GetDefaultValue(GetType());
-
-                var e = new AvaloniaPropertyChangedEventArgs(
-                    this,
-                    property,
-                    AvaloniaProperty.UnsetValue,
-                    value,
-                    BindingPriority.Unset);
-
-                property.NotifyInitialized(e);
-            }
-
-            foreach (var property in AvaloniaPropertyRegistry.Instance.GetRegistered(this))
-            {
-                Notify(property);
-            }
-
-            foreach (var property in AvaloniaPropertyRegistry.Instance.GetRegisteredAttached(this.GetType()))
-            {
-                Notify(property);
-            }
+            AvaloniaPropertyRegistry.Instance.NotifyInitialized(this);
         }
 
         /// <summary>
@@ -628,7 +586,7 @@ namespace Avalonia
         /// </summary>
         /// <param name="property">The property.</param>
         /// <returns>The default value.</returns>
-        internal object GetDefaultValue(AvaloniaProperty property)
+        private object GetDefaultValue(AvaloniaProperty property)
         {
             if (property.Inherits && InheritanceParent is AvaloniaObject aobj)
                 return aobj.GetValue(property);

+ 55 - 0
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@@ -5,6 +5,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Runtime.CompilerServices;
+using Avalonia.Data;
 
 namespace Avalonia
 {
@@ -23,6 +24,8 @@ namespace Avalonia
             new Dictionary<Type, List<AvaloniaProperty>>();
         private readonly Dictionary<Type, List<AvaloniaProperty>> _attachedCache =
             new Dictionary<Type, List<AvaloniaProperty>>();
+        private readonly Dictionary<Type, List<KeyValuePair<AvaloniaProperty, object>>> _initializedCache =
+            new Dictionary<Type, List<KeyValuePair<AvaloniaProperty, object>>>();
 
         /// <summary>
         /// Gets the <see cref="AvaloniaPropertyRegistry"/> instance
@@ -226,6 +229,7 @@ namespace Avalonia
             }
             
             _registeredCache.Clear();
+            _initializedCache.Clear();
         }
 
         /// <summary>
@@ -261,6 +265,57 @@ namespace Avalonia
             }
             
             _attachedCache.Clear();
+            _initializedCache.Clear();
+        }
+
+        internal void NotifyInitialized(AvaloniaObject o)
+        {
+            Contract.Requires<ArgumentNullException>(o != null);
+
+            var type = o.GetType();
+
+            void Notify(AvaloniaProperty property, object value)
+            {
+                var e = new AvaloniaPropertyChangedEventArgs(
+                    o,
+                    property,
+                    AvaloniaProperty.UnsetValue,
+                    value,
+                    BindingPriority.Unset);
+
+                property.NotifyInitialized(e);
+            }
+
+            if (!_initializedCache.TryGetValue(type, out var items))
+            {
+                var build = new Dictionary<AvaloniaProperty, object>();
+
+                foreach (var property in GetRegistered(type))
+                {
+                    var value = !property.IsDirect ?
+                        ((IStyledPropertyAccessor)property).GetDefaultValue(type) :
+                        null;
+                    build.Add(property, value);
+                }
+
+                foreach (var property in GetRegisteredAttached(type))
+                {
+                    if (!build.ContainsKey(property))
+                    {
+                        var value = ((IStyledPropertyAccessor)property).GetDefaultValue(type);
+                        build.Add(property, value);
+                    }
+                }
+
+                items = build.ToList();
+                _initializedCache.Add(type, items);
+            }
+
+            foreach (var i in items)
+            {
+                var value = i.Key.IsDirect ? o.GetValue(i.Key) : i.Value;
+                Notify(i.Key, value);
+            }
         }
     }
 }

+ 4 - 2
src/Avalonia.Styling/Styling/Style.cs

@@ -143,6 +143,7 @@ namespace Avalonia.Styling
                     }
 
                     controlSubscriptions.Add(subs);
+                    controlSubscriptions.Add(Disposable.Create(() => Subscriptions.Remove(subs)));
                     Subscriptions.Add(subs);
                 }
 
@@ -159,8 +160,9 @@ namespace Avalonia.Styling
                     var sub = setter.Apply(this, control, null);
                     subs.Add(sub);
                 }
-                
+
                 controlSubscriptions.Add(subs);
+                controlSubscriptions.Add(Disposable.Create(() => Subscriptions.Remove(subs)));
                 Subscriptions.Add(subs);
                 return true;
             }
@@ -223,7 +225,7 @@ namespace Avalonia.Styling
         {
             if (!_applied.TryGetValue(control, out var subscriptions))
             {
-                subscriptions = new CompositeDisposable(2);
+                subscriptions = new CompositeDisposable(3);
                 subscriptions.Add(control.StyleDetach.Subscribe(ControlDetach));
                 _applied.Add(control, subscriptions);
             }