Browse Source

Make TemplatedParent a direct property.

During initial layout, `TemplatedParent` is read tens of thousands of times. This being a styled property that used `inherits: true` meant that it was showing up in profiling as taking up a significant amount of time.

Make `TemplatedParent` a direct property so that reading it is a simple property access. This doesn't actually complicate the code much at all as once set the property value doesn't change, so `inherited: true` semantics are not that important.
Steven Kirk 7 years ago
parent
commit
e5cac827b1

+ 0 - 2
src/Avalonia.Controls/ItemsControl.cs

@@ -249,8 +249,6 @@ namespace Avalonia.Controls
                         if (containerControl != null)
                         {
                             ((ISetLogicalParent)containerControl).SetParent(this);
-                            containerControl.SetValue(TemplatedParentProperty, null);
-
                             containerControl.UpdateChild();
 
                             if (containerControl.Child != null)

+ 18 - 1
src/Avalonia.Controls/Primitives/TemplatedControl.cs

@@ -260,7 +260,7 @@ namespace Avalonia.Controls.Primitives
                     var child = template.Build(this);
                     var nameScope = new NameScope();
                     NameScope.SetNameScope((Control)child, nameScope);
-                    child.SetValue(TemplatedParentProperty, this);
+                    ApplyTemplatedParent(child);
                     RegisterNames(child, nameScope);
                     ((ISetLogicalParent)child).SetParent(this);
                     VisualChildren.Add(child);
@@ -326,6 +326,23 @@ namespace Avalonia.Controls.Primitives
             InvalidateMeasure();
         }
 
+        /// <summary>
+        /// Sets the TemplatedParent property for the created template children.
+        /// </summary>
+        /// <param name="control">The control.</param>
+        private void ApplyTemplatedParent(IControl control)
+        {
+            control.SetValue(TemplatedParentProperty, this);
+
+            foreach (var child in control.LogicalChildren)
+            {
+                if (child is IControl c)
+                {
+                    ApplyTemplatedParent(c);
+                }
+            }
+        }
+
         /// <summary>
         /// Registers each control with its name scope.
         /// </summary>

+ 4 - 2
src/Avalonia.Controls/Templates/TemplateExtensions.cs

@@ -24,12 +24,14 @@ namespace Avalonia.Controls.Templates
         {
             foreach (IControl child in control.GetVisualChildren())
             {
-                if (child.TemplatedParent == templatedParent)
+                var childTemplatedParent = child.TemplatedParent;
+
+                if (childTemplatedParent == templatedParent)
                 {
                     yield return child;
                 }
 
-                if (child.TemplatedParent != null)
+                if (childTemplatedParent != null)
                 {
                     foreach (var descendant in GetTemplateChildren(child, templatedParent))
                     {

+ 8 - 4
src/Avalonia.Styling/StyledElement.cs

@@ -49,8 +49,11 @@ namespace Avalonia
         /// <summary>
         /// Defines the <see cref="TemplatedParent"/> property.
         /// </summary>
-        public static readonly StyledProperty<ITemplatedControl> TemplatedParentProperty =
-            AvaloniaProperty.Register<StyledElement, ITemplatedControl>(nameof(TemplatedParent), inherits: true);
+        public static readonly DirectProperty<StyledElement, ITemplatedControl> TemplatedParentProperty =
+            AvaloniaProperty.RegisterDirect<StyledElement, ITemplatedControl>(
+                nameof(TemplatedParent),
+                o => o.TemplatedParent,
+                (o ,v) => o.TemplatedParent = v);
 
         private int _initCount;
         private string _name;
@@ -62,6 +65,7 @@ namespace Avalonia
         private Styles _styles;
         private bool _styled;
         private Subject<IStyleable> _styleDetach = new Subject<IStyleable>();
+        private ITemplatedControl _templatedParent;
         private bool _dataContextUpdating;
 
         /// <summary>
@@ -269,8 +273,8 @@ namespace Avalonia
         /// </summary>
         public ITemplatedControl TemplatedParent
         {
-            get { return GetValue(TemplatedParentProperty); }
-            internal set { SetValue(TemplatedParentProperty, value); }
+            get => _templatedParent;
+            internal set => SetAndRaise(TemplatedParentProperty, ref _templatedParent, value);
         }
 
         /// <summary>