Browse Source

Detect resources added in new styles.

Steven Kirk 8 years ago
parent
commit
2a61bbcb64

+ 3 - 0
src/Avalonia.Controls/Application.cs

@@ -125,6 +125,9 @@ namespace Avalonia
         /// </summary>
         IStyleHost IStyleHost.StylingParent => null;
 
+        /// <inheritdoc/>
+        bool IResourceProvider.HasResources => _resources?.Count > 0;
+
         /// <summary>
         /// Initializes the application by loading XAML etc.
         /// </summary>

+ 3 - 0
src/Avalonia.Controls/Control.cs

@@ -382,6 +382,9 @@ namespace Avalonia.Controls
         /// </summary>
         IAvaloniaReadOnlyList<ILogical> ILogical.LogicalChildren => LogicalChildren;
 
+        /// <inheritdoc/>
+        bool IResourceProvider.HasResources => _resources?.Count > 0 || Styles.HasResources;
+
         /// <inheritdoc/>
         IAvaloniaReadOnlyList<string> IStyleable.Classes => Classes;
 

+ 5 - 0
src/Avalonia.Styling/Controls/IResourceProvider.cs

@@ -12,6 +12,11 @@ namespace Avalonia.Controls
         /// </summary>
         event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
 
+        /// <summary>
+        /// Gets a value indicating whether the provider has resources.
+        /// </summary>
+        bool HasResources { get; }
+
         /// <summary>
         /// Tries to find a resource within the element.
         /// </summary>

+ 3 - 0
src/Avalonia.Styling/Styling/Style.cs

@@ -66,6 +66,9 @@ namespace Avalonia.Styling
         [Content]
         public IList<ISetter> Setters { get; set; } = new List<ISetter>();
 
+        /// <inheritdoc/>
+        bool IResourceProvider.HasResources => _resources?.Count > 0;
+
         /// <summary>
         /// Attaches the style to a control if the style's selector matches.
         /// </summary>

+ 21 - 2
src/Avalonia.Styling/Styling/Styles.cs

@@ -20,14 +20,33 @@ namespace Avalonia.Styling
         {
             ResetBehavior = ResetBehavior.Remove;
             this.ForEachItem(
-                x => x.ResourcesChanged += SubResourceChanged,
-                x => x.ResourcesChanged -= SubResourceChanged,
+                x =>
+                {
+                    if (x.HasResources)
+                    {
+                        ResourcesChanged?.Invoke(this, new ResourcesChangedEventArgs());
+                    }
+
+                    x.ResourcesChanged += SubResourceChanged;
+                },
+                x =>
+                {
+                    if (x.HasResources)
+                    {
+                        ResourcesChanged?.Invoke(this, new ResourcesChangedEventArgs());
+                    }
+
+                    x.ResourcesChanged -= SubResourceChanged;
+                },
                 () => { });
         }
 
         /// <inheritdoc/>
         public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
 
+        /// <inheritdoc/>
+        public bool HasResources => _resources?.Count > 0 || this.Any(x => x.HasResources);
+
         /// <summary>
         /// Gets or sets a dictionary of style resources.
         /// </summary>

+ 3 - 0
src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs

@@ -50,6 +50,9 @@ namespace Avalonia.Markup.Xaml.Styling
             }
         }
 
+        /// <inheritdoc/>
+        bool IResourceProvider.HasResources => Loaded.HasResources;
+
         /// <inheritdoc/>
         public void Attach(IStyleable control, IStyleHost container)
         {

+ 109 - 0
tests/Avalonia.Controls.UnitTests/ControlTests_Resources.cs

@@ -2,6 +2,8 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
+using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Templates;
 using Avalonia.Styling;
 using Avalonia.UnitTests;
 using Xunit;
@@ -142,5 +144,112 @@ namespace Avalonia.Controls.UnitTests
 
             Assert.Equal("foo-value", target.FindResource("foo"));
         }
+
+        [Fact]
+        public void Adding_Resource_Should_Call_Raise_ResourceChanged_On_Logical_Children()
+        {
+            Border child;
+
+            var target = new ContentControl
+            {
+                Content = child = new Border(),
+                Template = ContentControlTemplate(),
+            };
+
+            var raisedOnTarget = false;
+            var raisedOnPresenter = false;
+            var raisedOnChild = false;
+
+            target.Measure(Size.Infinity);
+            target.ResourcesChanged += (_, __) => raisedOnTarget = true;
+            target.Presenter.ResourcesChanged += (_, __) => raisedOnPresenter = true;
+            child.ResourcesChanged += (_, __) => raisedOnChild = true;
+
+            target.Resources.Add("foo", "bar");
+
+            Assert.True(raisedOnTarget);
+            Assert.False(raisedOnPresenter);
+            Assert.True(raisedOnChild);
+        }
+
+        [Fact]
+        public void Adding_Resource_To_Styles_Should_Raise_ResourceChanged()
+        {
+            var target = new Decorator();
+            var raised = false;
+
+            target.ResourcesChanged += (_, __) => raised = true;
+            target.Styles.Resources.Add("foo", "bar");
+
+            Assert.True(raised);
+        }
+
+        [Fact]
+        public void Adding_Resource_To_Nested_Style_Should_Raise_ResourceChanged()
+        {
+            Style style;
+            var target = new Decorator
+            {
+                Styles =
+                {
+                    (style = new Style()),
+                }
+            };
+
+            var raised = false;
+
+            target.ResourcesChanged += (_, __) => raised = true;
+            style.Resources.Add("foo", "bar");
+
+            Assert.True(raised);
+        }
+
+        [Fact]
+        public void Adding_Style_With_Resource_Should_Raise_ResourceChanged()
+        {
+            Style style = new Style
+            {
+                Resources = { { "foo", "bar" } },
+            };
+
+            var target = new Decorator();
+            var raised = false;
+
+            target.ResourcesChanged += (_, __) => raised = true;
+            target.Styles.Add(style);
+
+            Assert.True(raised);
+        }
+
+        [Fact]
+        public void Removing_Style_With_Resource_Should_Raise_ResourceChanged()
+        {
+            var target = new Decorator
+            {
+                Styles =
+                {
+                    new Style
+                    {
+                        Resources = { { "foo", "bar" } },
+                    }
+                }
+            };
+            var raised = false;
+
+            target.ResourcesChanged += (_, __) => raised = true;
+            target.Styles.Clear();
+
+            Assert.True(raised);
+        }
+
+        private IControlTemplate ContentControlTemplate()
+        {
+            return new FuncControlTemplate<ContentControl>(x =>
+                new ContentPresenter
+                {
+                    Name = "PART_ContentPresenter",
+                    [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
+                });
+        }
     }
 }