Explorar o código

Lazily initialize Styles.

Added an `IStyleHost.IsStylesInitialized` property to prevent the need for allocating empty `Styles` collections for many controls.
Steven Kirk %!s(int64=8) %!d(string=hai) anos
pai
achega
090a1ec8cf

+ 5 - 1
src/Avalonia.Controls/Application.cs

@@ -39,6 +39,7 @@ namespace Avalonia
         private readonly Lazy<IClipboard> _clipboard =
         private readonly Lazy<IClipboard> _clipboard =
             new Lazy<IClipboard>(() => (IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard)));
             new Lazy<IClipboard>(() => (IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard)));
         private readonly Styler _styler = new Styler();
         private readonly Styler _styler = new Styler();
+        private Styles _styles;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="Application"/> class.
         /// Initializes a new instance of the <see cref="Application"/> class.
@@ -109,13 +110,16 @@ namespace Avalonia
         /// <remarks>
         /// <remarks>
         /// Global styles apply to all windows in the application.
         /// Global styles apply to all windows in the application.
         /// </remarks>
         /// </remarks>
-        public Styles Styles { get; } = new Styles();
+        public Styles Styles => _styles ?? (_styles = new Styles());
 
 
         /// <summary>
         /// <summary>
         /// Gets the styling parent of the application, which is null.
         /// Gets the styling parent of the application, which is null.
         /// </summary>
         /// </summary>
         IStyleHost IStyleHost.StylingParent => null;
         IStyleHost IStyleHost.StylingParent => null;
 
 
+        /// <inheritdoc/>
+        bool IStyleHost.IsStylesInitialized => _styles != null;
+
         /// <summary>
         /// <summary>
         /// Initializes the application by loading XAML etc.
         /// Initializes the application by loading XAML etc.
         /// </summary>
         /// </summary>

+ 6 - 7
src/Avalonia.Controls/Control.cs

@@ -97,8 +97,8 @@ namespace Avalonia.Controls
         private bool _isAttachedToLogicalTree;
         private bool _isAttachedToLogicalTree;
         private IAvaloniaList<ILogical> _logicalChildren;
         private IAvaloniaList<ILogical> _logicalChildren;
         private INameScope _nameScope;
         private INameScope _nameScope;
-        private Styles _styles;
         private bool _styled;
         private bool _styled;
+        private Styles _styles;
         private Subject<IStyleable> _styleDetach = new Subject<IStyleable>();
         private Subject<IStyleable> _styleDetach = new Subject<IStyleable>();
 
 
         /// <summary>
         /// <summary>
@@ -259,18 +259,14 @@ namespace Avalonia.Controls
         public bool IsInitialized { get; private set; }
         public bool IsInitialized { get; private set; }
 
 
         /// <summary>
         /// <summary>
-        /// Gets or sets the styles for the control.
+        /// Gets the styles for the control.
         /// </summary>
         /// </summary>
         /// <remarks>
         /// <remarks>
         /// Styles for the entire application are added to the Application.Styles collection, but
         /// Styles for the entire application are added to the Application.Styles collection, but
         /// each control may in addition define its own styles which are applied to the control
         /// each control may in addition define its own styles which are applied to the control
         /// itself and its children.
         /// itself and its children.
         /// </remarks>
         /// </remarks>
-        public Styles Styles
-        {
-            get { return _styles ?? (_styles = new Styles()); }
-            set { _styles = value; }
-        }
+        public Styles Styles => _styles ?? (_styles = new Styles());
 
 
         /// <summary>
         /// <summary>
         /// Gets the control's logical parent.
         /// Gets the control's logical parent.
@@ -336,6 +332,9 @@ namespace Avalonia.Controls
         /// <inheritdoc/>
         /// <inheritdoc/>
         IObservable<IStyleable> IStyleable.StyleDetach => _styleDetach;
         IObservable<IStyleable> IStyleable.StyleDetach => _styleDetach;
 
 
+        /// <inheritdoc/>
+        bool IStyleHost.IsStylesInitialized => _styles != null;
+
         /// <inheritdoc/>
         /// <inheritdoc/>
         IStyleHost IStyleHost.StylingParent => (IStyleHost)InheritanceParent;
         IStyleHost IStyleHost.StylingParent => (IStyleHost)InheritanceParent;
 
 

+ 1 - 1
src/Avalonia.Diagnostics/Views/ControlDetailsView.cs

@@ -42,7 +42,7 @@ namespace Avalonia.Diagnostics.Views
             {
             {
                 Content = _grid = new SimpleGrid
                 Content = _grid = new SimpleGrid
                 {
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                     {
                         new Style(x => x.Is<Control>())
                         new Style(x => x.Is<Control>())
                         {
                         {

+ 11 - 1
src/Avalonia.Styling/Styling/IStyleHost.cs

@@ -1,6 +1,8 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 
+using System;
+
 namespace Avalonia.Styling
 namespace Avalonia.Styling
 {
 {
     /// <summary>
     /// <summary>
@@ -8,6 +10,15 @@ namespace Avalonia.Styling
     /// </summary>
     /// </summary>
     public interface IStyleHost
     public interface IStyleHost
     {
     {
+        /// <summary>
+        /// Gets a value indicating whether <see cref="Styles"/> is initialized.
+        /// </summary>
+        /// <remarks>
+        /// The <see cref="Styles"/> property may be lazily initialized, if so this property
+        /// indicates whether it has been initialized.
+        /// </remarks>
+        bool IsStylesInitialized { get; }
+
         /// <summary>
         /// <summary>
         /// Gets the styles for the element.
         /// Gets the styles for the element.
         /// </summary>
         /// </summary>
@@ -17,6 +28,5 @@ namespace Avalonia.Styling
         /// Gets the parent style host element.
         /// Gets the parent style host element.
         /// </summary>
         /// </summary>
         IStyleHost StylingParent { get; }
         IStyleHost StylingParent { get; }
-
     }
     }
 }
 }

+ 7 - 4
src/Avalonia.Styling/Styling/StyleExtensions.cs

@@ -23,11 +23,14 @@ namespace Avalonia.Styling
 
 
             while (control != null)
             while (control != null)
             {
             {
-                var result = control.Styles.FindResource(name);
-
-                if (result != AvaloniaProperty.UnsetValue)
+                if (control.IsStylesInitialized)
                 {
                 {
-                    return result;
+                    var result = control.Styles.FindResource(name);
+
+                    if (result != AvaloniaProperty.UnsetValue)
+                    {
+                        return result;
+                    }
                 }
                 }
 
 
                 control = control.StylingParent;
                 control = control.StylingParent;

+ 4 - 1
src/Avalonia.Styling/Styling/Styler.cs

@@ -29,7 +29,10 @@ namespace Avalonia.Styling
                 ApplyStyles(control, parentContainer);
                 ApplyStyles(control, parentContainer);
             }
             }
 
 
-            styleHost.Styles.Attach(control, styleHost);
+            if (styleHost.IsStylesInitialized)
+            {
+                styleHost.Styles.Attach(control, styleHost);
+            }
         }
         }
     }
     }
 }
 }

+ 1 - 0
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@@ -265,6 +265,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
             };
             };
 
 
             var globalStyles = new Mock<IGlobalStyles>();
             var globalStyles = new Mock<IGlobalStyles>();
+            globalStyles.Setup(x => x.IsStylesInitialized).Returns(true);
             globalStyles.Setup(x => x.Styles).Returns(styles);
             globalStyles.Setup(x => x.Styles).Returns(styles);
 
 
             var renderInterface = new Mock<IPlatformRenderInterface>();
             var renderInterface = new Mock<IPlatformRenderInterface>();

+ 4 - 4
tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs

@@ -399,7 +399,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 TestTemplatedControl target;
                 TestTemplatedControl target;
                 var root = new TestRoot
                 var root = new TestRoot
                 {
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                     {
                         new Style(x => x.OfType<TestTemplatedControl>())
                         new Style(x => x.OfType<TestTemplatedControl>())
                         {
                         {
@@ -435,7 +435,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 TestTemplatedControl target;
                 TestTemplatedControl target;
                 var root = new TestRoot
                 var root = new TestRoot
                 {
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                     {
                         new Style(x => x.OfType<TestTemplatedControl>())
                         new Style(x => x.OfType<TestTemplatedControl>())
                         {
                         {
@@ -474,7 +474,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
 
 
                 var root = new TestRoot
                 var root = new TestRoot
                 {
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                     {
                         new Style(x => x.OfType<TestTemplatedControl>())
                         new Style(x => x.OfType<TestTemplatedControl>())
                         {
                         {
@@ -494,7 +494,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
 
 
                 var root2 = new TestRoot
                 var root2 = new TestRoot
                 {
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                     {
                         new Style(x => x.OfType<TestTemplatedControl>())
                         new Style(x => x.OfType<TestTemplatedControl>())
                         {
                         {

+ 1 - 1
tests/Avalonia.Controls.UnitTests/TabControlTests.cs

@@ -135,7 +135,7 @@ namespace Avalonia.Controls.UnitTests
             {
             {
                 var root = new TestRoot
                 var root = new TestRoot
                 {
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                     {
                         new Style(x => x.OfType<TabItem>())
                         new Style(x => x.OfType<TabItem>())
                         {
                         {

+ 1 - 1
tests/Avalonia.Controls.UnitTests/UserControlTests.cs

@@ -21,7 +21,7 @@ namespace Avalonia.Controls.UnitTests
                 var target = new UserControl();
                 var target = new UserControl();
                 var root = new TestRoot
                 var root = new TestRoot
                 {
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                     {
                         new Style(x => x.OfType<ContentControl>())
                         new Style(x => x.OfType<ContentControl>())
                         {
                         {

+ 1 - 0
tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

@@ -193,6 +193,7 @@ namespace Avalonia.Layout.UnitTests
                 .Bind<IWindowingPlatform>().ToConstant(new Avalonia.Controls.UnitTests.WindowingPlatformMock(() => windowImpl.Object));
                 .Bind<IWindowingPlatform>().ToConstant(new Avalonia.Controls.UnitTests.WindowingPlatformMock(() => windowImpl.Object));
 
 
             var theme = new DefaultTheme();
             var theme = new DefaultTheme();
+            globalStyles.Setup(x => x.IsStylesInitialized).Returns(true);
             globalStyles.Setup(x => x.Styles).Returns(theme);
             globalStyles.Setup(x => x.Styles).Returns(theme);
         }
         }
     }
     }

+ 10 - 10
tests/Avalonia.Styling.UnitTests/ResourceTests.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Styling.UnitTests
 
 
             var tree = new Decorator
             var tree = new Decorator
             {
             {
-                Styles = new Styles
+                Styles =
                 {
                 {
                     new Style
                     new Style
                     {
                     {
@@ -29,7 +29,7 @@ namespace Avalonia.Styling.UnitTests
                 },
                 },
                 Child = target = new Border
                 Child = target = new Border
                 {
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                     {
                         new Style
                         new Style
                         {
                         {
@@ -60,16 +60,16 @@ namespace Avalonia.Styling.UnitTests
 
 
             var tree = target = new Border
             var tree = target = new Border
             {
             {
-                Styles = new Styles
+                Styles =
+                {
+                    new Style
                     {
                     {
-                        new Style
+                        Resources = new StyleResources
                         {
                         {
-                            Resources = new StyleResources
-                            {
-                                { "Foo", "foo" },
-                            }
-                        },
-                    }
+                            { "Foo", "foo" },
+                        }
+                    },
+                }
             };
             };
 
 
             Assert.Equal(AvaloniaProperty.UnsetValue, target.FindStyleResource("Baz"));
             Assert.Equal(AvaloniaProperty.UnsetValue, target.FindStyleResource("Baz"));