Pārlūkot izejas kodu

Merge pull request #626 from AvaloniaUI/fix-transformed-bounds

Fix TransformedBounds for invisible controls.
Jeremy Koritzinsky 9 gadi atpakaļ
vecāks
revīzija
7577e0ef69

+ 4 - 4
src/Avalonia.Controls/Primitives/AdornerLayer.cs

@@ -57,11 +57,11 @@ namespace Avalonia.Controls.Primitives
             {
                 var info = (AdornedElementInfo)child.GetValue(s_adornedElementInfoProperty);
 
-                if (info != null)
+                if (info != null && info.Bounds.HasValue)
                 {
-                    child.RenderTransform = new MatrixTransform(info.Bounds.Transform);
+                    child.RenderTransform = new MatrixTransform(info.Bounds.Value.Transform);
                     child.RenderTransformOrigin = new RelativePoint(new Point(0,0), RelativeUnit.Absolute);
-                    child.Arrange(info.Bounds.Bounds);
+                    child.Arrange(info.Bounds.Value.Bounds);
                 }
                 else
                 {
@@ -130,7 +130,7 @@ namespace Avalonia.Controls.Primitives
         {
             public IDisposable Subscription { get; set; }
 
-            public TransformedBounds Bounds { get; set; }
+            public TransformedBounds? Bounds { get; set; }
         }
     }
 }

+ 17 - 0
src/Avalonia.SceneGraph/Rendering/RendererMixin.cs

@@ -142,11 +142,28 @@ namespace Avalonia.Rendering
                             var childClipRect = clipRect.Translate(-childBounds.Position);
                             context.Render(child, childClipRect);
                         }
+                        else
+                        {
+                            ClearTransformedBounds(child);
+                        }
                     }
 
                     ReturnListToPool(lst);
                 }
             }
+            
+            if (!visual.IsVisible)
+            {
+                ClearTransformedBounds(visual);
+            }
+        }
+
+        private static void ClearTransformedBounds(IVisual visual)
+        {
+            foreach (var e in visual.GetSelfAndVisualDescendents())
+            {
+                BoundsTracker.SetTransformedBounds((Visual)visual, null);
+            }
         }
 
         private static void ReturnListToPool(List<IVisual> lst)

+ 18 - 8
src/Avalonia.SceneGraph/VisualTree/BoundsTracker.cs

@@ -9,33 +9,43 @@ namespace Avalonia.VisualTree
     /// Tracks the bounds of a control.
     /// </summary>
     /// <remarks>
-    /// This class is used by Adorners to track the control that the adorner is attached to.
+    /// This class is used to track a controls's bounds for hit testing.
+    /// TODO: This shouldn't be implemented as an attached property: it would be more performant
+    /// to just store bounds in some sort of central repository.
     /// </remarks>
     public class BoundsTracker
     {
-        private static AttachedProperty<TransformedBounds> TransformedBoundsProperty =
-            AvaloniaProperty.RegisterAttached<BoundsTracker, Visual, TransformedBounds>("TransformedBounds");
+        /// <summary>
+        /// Defines the TransformedBounds attached property.
+        /// </summary>
+        private static AttachedProperty<TransformedBounds?> TransformedBoundsProperty =
+            AvaloniaProperty.RegisterAttached<BoundsTracker, Visual, TransformedBounds?>("TransformedBounds");
 
         /// <summary>
         /// Starts tracking the specified visual.
         /// </summary>
         /// <param name="visual">The visual.</param>
         /// <returns>An observable that returns the tracked bounds.</returns>
-        public IObservable<TransformedBounds> Track(Visual visual)
+        public IObservable<TransformedBounds?> Track(Visual visual)
         {
             return visual.GetObservable(TransformedBoundsProperty);
         }
 
-        internal static void SetTransformedBounds(Visual visual, TransformedBounds bounds)
+        /// <summary>
+        /// Sets the transformed bounds of the visual.
+        /// </summary>
+        /// <param name="visual">The visual.</param>
+        /// <param name="value">The transformed bounds.</param>
+        internal static void SetTransformedBounds(Visual visual, TransformedBounds? value)
         {
-            visual.SetValue(TransformedBoundsProperty, bounds);
+            visual.SetValue(TransformedBoundsProperty, value);
         }
 
         /// <summary>
         /// Gets the transformed bounds of the visual.
         /// </summary>
         /// <param name="visual">The visual.</param>
-        /// <returns>The transformed bounds.</returns>
-        public static TransformedBounds GetTransformedBounds(Visual visual) => visual.GetValue(TransformedBoundsProperty);
+        /// <returns>The transformed bounds or null if the visual is not visible.</returns>
+        public static TransformedBounds? GetTransformedBounds(Visual visual) => visual.GetValue(TransformedBoundsProperty);
     }
 }

+ 1 - 1
src/Avalonia.SceneGraph/VisualTree/VisualExtensions.cs

@@ -104,7 +104,7 @@ namespace Avalonia.VisualTree
 
             if (filter?.Invoke(visual) != false)
             {
-                bool containsPoint = BoundsTracker.GetTransformedBounds((Visual)visual).Contains(p);
+                bool containsPoint = BoundsTracker.GetTransformedBounds((Visual)visual)?.Contains(p) == true;
 
                 if ((containsPoint || !visual.ClipToBounds) && visual.VisualChildren.Any())
                 {

+ 3 - 3
tests/Avalonia.SceneGraph.UnitTests/VisualTree/BoundsTrackerTests.cs

@@ -46,11 +46,11 @@ namespace Avalonia.SceneGraph.UnitTests.VisualTree
                 context.Render(tree);
 
                 var track = target.Track(control);
-                var results = new List<TransformedBounds>();
+                var results = new List<TransformedBounds?>();
                 track.Subscribe(results.Add);
 
-                Assert.Equal(new Rect(0, 0, 15, 15), results[0].Bounds);
-                Assert.Equal(Matrix.CreateTranslation(42, 42), results[0].Transform);
+                Assert.Equal(new Rect(0, 0, 15, 15), results[0].Value.Bounds);
+                Assert.Equal(Matrix.CreateTranslation(42, 42), results[0].Value.Transform);
             }
         }
     }