Sfoglia il codice sorgente

Fix height queries not matching when container name is set, remove unused query grammer and allow nesting selector in container styles (#18659)

* fix height queries not matching when container name is set, remove unused query grammer

* add unit test for height container queries with name

---------

Co-authored-by: Julien Lebosquain <[email protected]>
Emmanuel Hansen 6 mesi fa
parent
commit
b8e4be76a3

+ 8 - 0
src/Avalonia.Base/Styling/NestingSelector.cs

@@ -27,6 +27,14 @@ namespace Avalonia.Styling
                     SelectorMatch.AlwaysThisType :
                     SelectorMatch.NeverThisType;
             }
+            else if (parent is ContainerQuery query && query.Parent is ControlTheme queryTheme)
+            {
+                if (queryTheme.TargetType is null)
+                    throw new InvalidOperationException("ControlTheme has no TargetType.");
+                return queryTheme.TargetType.IsAssignableFrom(StyledElement.GetStyleKey(control)) ?
+                    SelectorMatch.AlwaysThisType :
+                    SelectorMatch.NeverThisType;
+            }
 
             throw new InvalidOperationException(
                 "Nesting selector was specified but cannot determine parent selector.");

+ 4 - 4
src/Avalonia.Base/Styling/ScreenQueries.cs

@@ -64,7 +64,7 @@ namespace Avalonia.Styling
             }
 
             return IsTrue(argument.@operator, argument.value) ?
-                new SelectorMatch(SelectorMatchResult.AlwaysThisInstance) : SelectorMatch.NeverThisInstance;
+                SelectorMatch.AlwaysThisInstance : SelectorMatch.NeverThisInstance;
         }
 
         public override string ToString() => "width";
@@ -90,7 +90,7 @@ namespace Avalonia.Styling
 
             if (subscribe)
             {
-                return new SelectorMatch(new HeightActivator(visual, Argument));
+                return new SelectorMatch(new HeightActivator(visual, Argument, containerName));
             }
 
             if (ContainerQueryActivatorBase.GetContainer(visual, containerName) is { } container
@@ -104,9 +104,9 @@ namespace Avalonia.Styling
             return SelectorMatch.NeverThisInstance;
         }
 
-        internal static SelectorMatch Evaluate(VisualQueryProvider screenSizeProvider, (StyleQueryComparisonOperator @operator, double value) argument)
+        internal static SelectorMatch Evaluate(VisualQueryProvider queryProvider, (StyleQueryComparisonOperator @operator, double value) argument)
         {
-            var height = screenSizeProvider.Height;
+            var height = queryProvider.Height;
             if (double.IsNaN(height))
             {
                 return SelectorMatch.NeverThisInstance;

+ 0 - 44
src/Markup/Avalonia.Markup/Markup/Parsers/ContainerQueryGrammar.cs

@@ -169,50 +169,6 @@ namespace Avalonia.Markup.Parsers
 
             return double.Parse(number.ToString());
         }
-        
-        private static StyleQueryComparisonOperator ParseOperator(ref CharacterReader r)
-        {
-            r.SkipWhitespace();
-            var queryOperator = r.TakeWhile(x => !char.IsWhiteSpace(x));
-
-            return queryOperator.ToString() switch
-            {
-                "=" => StyleQueryComparisonOperator.Equals,
-                "<" => StyleQueryComparisonOperator.LessThan,
-                ">" => StyleQueryComparisonOperator.GreaterThan,
-                "<=" => StyleQueryComparisonOperator.LessThanOrEquals,
-                ">=" => StyleQueryComparisonOperator.GreaterThanOrEquals,
-                "" => StyleQueryComparisonOperator.None,
-                _ => throw new ExpressionParseException(r.Position, $"Expected a comparison operator after.")
-            };
-        }
-        
-        private static T ParseEnum<T>(ref CharacterReader r) where T: struct
-        {
-            var identifier = r.ParseIdentifier();
-
-            if (Enum.TryParse<T>(identifier.ToString(), true, out T value))
-                return value;
-
-            throw new ExpressionParseException(r.Position, $"Expected a {typeof(T)} after.");
-        }
-        
-        private static string ParseString(ref CharacterReader r) 
-        {
-            return r.ParseIdentifier().ToString();
-        }
-
-        private static void Expect(ref CharacterReader r, char c)
-        {
-            if (r.End)
-            {
-                throw new ExpressionParseException(r.Position, $"Expected '{c}', got end of selector.");
-            }
-            else if (!r.TakeIf(')'))
-            {
-                throw new ExpressionParseException(r.Position, $"Expected '{c}', got '{r.Peek}'.");
-            }
-        }
 
         public class OrSyntax : ISyntax
         {

+ 52 - 1
tests/Avalonia.Base.UnitTests/Styling/ContainerTests.cs

@@ -111,7 +111,7 @@ namespace Avalonia.Base.UnitTests.Styling
         }
 
         [Fact]
-        public void Container_Queries_Matches_Name()
+        public void Container_Width_Queries_Matches_Name()
         {
             using var app = UnitTestApplication.Start();
             var root = new LayoutTestRoot()
@@ -160,5 +160,56 @@ namespace Avalonia.Base.UnitTests.Styling
             root.LayoutManager.ExecuteLayoutPass();
             Assert.Equal(child.Width, 300.0);
         }
+
+        [Fact]
+        public void Container_Height_Queries_Matches_Name()
+        {
+            using var app = UnitTestApplication.Start();
+            var root = new LayoutTestRoot()
+            {
+                ClientSize = new Size(600, 600)
+            };
+            var containerQuery1 = new ContainerQuery(x => new HeightQuery(x, StyleQueryComparisonOperator.LessThanOrEquals, 500));
+            containerQuery1.Children.Add(new Style(x => x.Is<Border>())
+            {
+                Setters = { new Setter(Control.HeightProperty, 200.0) }
+            });
+            var containerQuery2 = new ContainerQuery(x => new HeightQuery(x, StyleQueryComparisonOperator.LessThanOrEquals, 500), "TEST");
+            containerQuery2.Children.Add(new Style(x => x.Is<Border>())
+            {
+                Setters = { new Setter(Control.HeightProperty, 300.0) }
+            });
+            root.Styles.Add(containerQuery2);
+            root.Styles.Add(containerQuery1);
+            var child = new Border()
+            {
+                Name = "Child",
+                VerticalAlignment = Avalonia.Layout.VerticalAlignment.Stretch
+            };
+            var controlInner = new ContentControl()
+            {
+                Width = 400,
+                Height = 400,
+                Content = child,
+                Name = "Inner"
+            };
+            Container.SetSizing(controlInner, Avalonia.Styling.ContainerSizing.Height);
+            Container.SetName(controlInner, "TEST");
+            var border = new Border()
+            {
+                HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch,
+                VerticalAlignment = Avalonia.Layout.VerticalAlignment.Stretch,
+                Child = controlInner,
+                Name = "Parent"
+            };
+            Container.SetSizing(border, Avalonia.Styling.ContainerSizing.Height);
+
+            root.Child = border;
+
+            root.LayoutManager.ExecuteInitialLayoutPass();
+
+            root.LayoutManager.ExecuteLayoutPass();
+            Assert.Equal(child.Height, 300.0);
+        }
     }
 }