Browse Source

Use shared StyleInstance if possible.

If a `StyleBase` has no activator, and its `Setter`s don't need to be separately instanced on the control, then we can share a `StyleInstance` between controls.

This causes failing tests because `TopLevel` applies styles in its constructor, but doesn't set `_styled` to true, meaning that styles get applied twice. This issue will need to be addressed separately.
Steven Kirk 3 years ago
parent
commit
56c098f77e
1 changed files with 21 additions and 5 deletions
  1. 21 5
      src/Avalonia.Base/Styling/StyleBase.cs

+ 21 - 5
src/Avalonia.Base/Styling/StyleBase.cs

@@ -19,6 +19,7 @@ namespace Avalonia.Styling
         private List<ISetter>? _setters;
         private List<IAnimation>? _animations;
         private StyleCache? _childCache;
+        private StyleInstance? _sharedInstance;
 
         public IList<IStyle> Children => _children ??= new(this);
 
@@ -86,15 +87,30 @@ namespace Avalonia.Styling
             if (target is not AvaloniaObject ao)
                 throw new InvalidOperationException("Styles can only be applied to AvaloniaObjects.");
 
-            var instance = new StyleInstance(this, activator);
+            StyleInstance instance;
 
-            if (_setters is object)
+            if (_sharedInstance is not null)
             {
-                foreach (var setter in _setters)
+                instance = _sharedInstance;
+            }
+            else
+            {
+                var canShareInstance = activator is null;
+
+                instance = new StyleInstance(this, activator);
+
+                if (_setters is object)
                 {
-                    var setterInstance = setter.Instance(instance, target);
-                    instance.Add(setterInstance);
+                    foreach (var setter in _setters)
+                    {
+                        var setterInstance = setter.Instance(instance, target);
+                        instance.Add(setterInstance);
+                        canShareInstance &= setterInstance == setter;
+                    }
                 }
+
+                if (canShareInstance)
+                    _sharedInstance = instance;
             }
 
             ao.GetValueStore().AddFrame(instance);