瀏覽代碼

Removed a number of interfaces.

`IAvaloniaObject`, `IControl`, `ILayoutable`, `IPanel`, `IStyledElement`, `IVisual`.
Steven Kirk 3 年之前
父節點
當前提交
ec74057151
共有 100 個文件被更改,包括 505 次插入751 次删除
  1. 3 3
      samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
  2. 1 1
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  3. 1 1
      src/Avalonia.Base/Animation/PageSlide.cs
  4. 1 1
      src/Avalonia.Base/AttachedProperty.cs
  5. 1 1
      src/Avalonia.Base/AvaloniaObject.cs
  6. 38 62
      src/Avalonia.Base/AvaloniaObjectExtensions.cs
  7. 11 11
      src/Avalonia.Base/AvaloniaProperty.cs
  8. 3 3
      src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
  9. 2 2
      src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
  10. 6 6
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs
  11. 1 1
      src/Avalonia.Base/AvaloniaProperty`1.cs
  12. 2 2
      src/Avalonia.Base/ClassBindingManager.cs
  13. 1 1
      src/Avalonia.Base/Controls/Classes.cs
  14. 1 1
      src/Avalonia.Base/Controls/ISetInheritanceParent.cs
  15. 2 1
      src/Avalonia.Base/Controls/ResourceNodeExtensions.cs
  16. 2 2
      src/Avalonia.Base/Data/BindingOperations.cs
  17. 2 2
      src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs
  18. 1 1
      src/Avalonia.Base/Data/IBinding.cs
  19. 3 3
      src/Avalonia.Base/Data/IndexerBinding.cs
  20. 1 1
      src/Avalonia.Base/Data/InstancedBinding.cs
  21. 1 1
      src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs
  22. 5 5
      src/Avalonia.Base/DirectProperty.cs
  23. 3 3
      src/Avalonia.Base/DirectPropertyBase.cs
  24. 0 79
      src/Avalonia.Base/IAvaloniaObject.cs
  25. 1 1
      src/Avalonia.Base/IDataContextProvider.cs
  26. 2 2
      src/Avalonia.Base/IDirectPropertyAccessor.cs
  27. 0 39
      src/Avalonia.Base/IStyledElement.cs
  28. 2 2
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  29. 3 2
      src/Avalonia.Base/Input/DragDropDevice.cs
  30. 1 1
      src/Avalonia.Base/Input/DragEventArgs.cs
  31. 10 7
      src/Avalonia.Base/Input/FocusManager.cs
  32. 2 2
      src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs
  33. 2 2
      src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs
  34. 3 3
      src/Avalonia.Base/Input/Gestures.cs
  35. 7 2
      src/Avalonia.Base/Input/IInputElement.cs
  36. 1 1
      src/Avalonia.Base/Input/IMainMenu.cs
  37. 9 8
      src/Avalonia.Base/Input/InputExtensions.cs
  38. 22 17
      src/Avalonia.Base/Input/KeyboardDevice.cs
  39. 1 1
      src/Avalonia.Base/Input/KeyboardNavigation.cs
  40. 3 3
      src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
  41. 7 7
      src/Avalonia.Base/Input/MouseDevice.cs
  42. 10 2
      src/Avalonia.Base/Input/Navigation/FocusExtensions.cs
  43. 10 8
      src/Avalonia.Base/Input/Navigation/TabNavigation.cs
  44. 3 3
      src/Avalonia.Base/Input/PenDevice.cs
  45. 10 10
      src/Avalonia.Base/Input/Pointer.cs
  46. 1 1
      src/Avalonia.Base/Input/PointerDeltaEventArgs.cs
  47. 9 9
      src/Avalonia.Base/Input/PointerEventArgs.cs
  48. 31 17
      src/Avalonia.Base/Input/PointerOverPreProcessor.cs
  49. 1 1
      src/Avalonia.Base/Input/PointerWheelEventArgs.cs
  50. 1 1
      src/Avalonia.Base/Input/TappedEventArgs.cs
  51. 1 1
      src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs
  52. 6 3
      src/Avalonia.Base/Input/TextInput/InputMethodManager.cs
  53. 3 3
      src/Avalonia.Base/Input/TextInput/TransformTrackingHelper.cs
  54. 3 3
      src/Avalonia.Base/Input/TouchDevice.cs
  55. 1 1
      src/Avalonia.Base/Interactivity/Interactive.cs
  56. 1 1
      src/Avalonia.Base/Layout/AttachedLayout.cs
  57. 7 7
      src/Avalonia.Base/Layout/ElementManager.cs
  58. 5 5
      src/Avalonia.Base/Layout/FlowLayoutAlgorithm.cs
  59. 3 3
      src/Avalonia.Base/Layout/IFlowLayoutAlgorithmDelegates.cs
  60. 4 4
      src/Avalonia.Base/Layout/ILayoutManager.cs
  61. 1 1
      src/Avalonia.Base/Layout/ILayoutRoot.cs
  62. 0 122
      src/Avalonia.Base/Layout/ILayoutable.cs
  63. 2 2
      src/Avalonia.Base/Layout/LayoutContextAdapter.cs
  64. 22 21
      src/Avalonia.Base/Layout/LayoutHelper.cs
  65. 19 19
      src/Avalonia.Base/Layout/LayoutManager.cs
  66. 16 19
      src/Avalonia.Base/Layout/Layoutable.cs
  67. 2 2
      src/Avalonia.Base/Layout/NonVirtualizingLayoutContext.cs
  68. 4 4
      src/Avalonia.Base/Layout/NonVirtualizingStackLayout.cs
  69. 6 6
      src/Avalonia.Base/Layout/StackLayout.cs
  70. 3 3
      src/Avalonia.Base/Layout/UniformGridLayout.cs
  71. 2 2
      src/Avalonia.Base/Layout/UniformGridLayoutState.cs
  72. 4 4
      src/Avalonia.Base/Layout/VirtualLayoutContextAdapter.cs
  73. 6 6
      src/Avalonia.Base/Layout/VirtualizingLayoutContext.cs
  74. 1 1
      src/Avalonia.Base/Layout/WrapLayout/WrapItem.cs
  75. 2 2
      src/Avalonia.Base/Media/IVisualBrush.cs
  76. 1 1
      src/Avalonia.Base/Media/Imaging/RenderTargetBitmap.cs
  77. 2 2
      src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
  78. 5 5
      src/Avalonia.Base/Media/VisualBrush.cs
  79. 1 1
      src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
  80. 0 12
      src/Avalonia.Base/PropertyStore/UntypedValueUtils.cs
  81. 3 3
      src/Avalonia.Base/Reactive/AvaloniaPropertyBindingObservable.cs
  82. 3 3
      src/Avalonia.Base/Reactive/AvaloniaPropertyChangedObservable.cs
  83. 14 22
      src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs
  84. 7 7
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  85. 11 11
      src/Avalonia.Base/Rendering/DeferredRenderer.cs
  86. 7 7
      src/Avalonia.Base/Rendering/DirtyVisuals.cs
  87. 2 2
      src/Avalonia.Base/Rendering/ICustomSimpleHitTest.cs
  88. 1 1
      src/Avalonia.Base/Rendering/IRenderRoot.cs
  89. 4 4
      src/Avalonia.Base/Rendering/IRenderer.cs
  90. 19 19
      src/Avalonia.Base/Rendering/ImmediateRenderer.cs
  91. 2 2
      src/Avalonia.Base/Rendering/RenderLayer.cs
  92. 3 4
      src/Avalonia.Base/Rendering/RenderLayers.cs
  93. 2 2
      src/Avalonia.Base/Rendering/SceneGraph/ISceneBuilder.cs
  94. 2 3
      src/Avalonia.Base/Rendering/SceneGraph/IVisualNode.cs
  95. 20 20
      src/Avalonia.Base/Rendering/SceneGraph/Scene.cs
  96. 9 9
      src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs
  97. 2 3
      src/Avalonia.Base/Rendering/SceneGraph/SceneLayer.cs
  98. 11 11
      src/Avalonia.Base/Rendering/SceneGraph/SceneLayers.cs
  99. 3 3
      src/Avalonia.Base/Rendering/SceneGraph/VisualNode.cs
  100. 3 3
      src/Avalonia.Base/Rendering/ZIndexComparer.cs

+ 3 - 3
samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs

@@ -293,10 +293,10 @@ namespace ControlCatalog.ViewModels
         /// <remarks>
         /// Any one of the parameters may be null, but not both.
         /// </remarks>
-        private static IVisual GetVisualParent(IVisual? from, IVisual? to)
+        private static Visual GetVisualParent(Visual? from, Visual? to)
         {
-            var p1 = (from ?? to)!.VisualParent;
-            var p2 = (to ?? from)!.VisualParent;
+            var p1 = (from ?? to)!.GetVisualParent();
+            var p2 = (to ?? from)!.GetVisualParent();
 
             if (p1 != null && p2 != null && p1 != p2)
             {

+ 1 - 1
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@@ -109,7 +109,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
                 ? new CompositingRenderer(root, AndroidPlatform.Compositor)
                 : AndroidPlatform.Options.UseDeferredRendering
                     ? new DeferredRenderer(root, AvaloniaLocator.Current.GetRequiredService<IRenderLoop>()) { RenderOnlyOnRenderThread = true }
-                    : new ImmediateRenderer(root);
+                    : new ImmediateRenderer((Visual)root);
 
         public virtual void Hide()
         {

+ 1 - 1
src/Avalonia.Base/Animation/PageSlide.cs

@@ -157,7 +157,7 @@ namespace Avalonia.Animation
         /// <remarks>
         /// Any one of the parameters may be null, but not both.
         /// </remarks>
-        protected static IVisual GetVisualParent(IVisual? from, IVisual? to)
+        protected static Visual GetVisualParent(Visual? from, Visual? to)
         {
             var p1 = (from ?? to)!.VisualParent;
             var p2 = (to ?? from)!.VisualParent;

+ 1 - 1
src/Avalonia.Base/AttachedProperty.cs

@@ -34,7 +34,7 @@ namespace Avalonia
         /// </summary>
         /// <typeparam name="TOwner">The owner type.</typeparam>
         /// <returns>The property.</returns>
-        public new AttachedProperty<TValue> AddOwner<TOwner>() where TOwner : IAvaloniaObject
+        public new AttachedProperty<TValue> AddOwner<TOwner>() where TOwner : AvaloniaObject
         {
             AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), this);
             return this;

+ 1 - 1
src/Avalonia.Base/AvaloniaObject.cs

@@ -16,7 +16,7 @@ namespace Avalonia
     /// <remarks>
     /// This class is analogous to DependencyObject in WPF.
     /// </remarks>
-    public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged
+    public class AvaloniaObject : IAvaloniaObjectDebug, INotifyPropertyChanged
     {
         private readonly ValueStore _values;
         private AvaloniaObject? _inheritanceParent;

+ 38 - 62
src/Avalonia.Base/AvaloniaObjectExtensions.cs

@@ -36,7 +36,7 @@ namespace Avalonia
         /// <remarks>
         /// The subscription to <paramref name="o"/> is created using a weak reference.
         /// </remarks>
-        public static IObservable<object?> GetObservable(this IAvaloniaObject o, AvaloniaProperty property)
+        public static IObservable<object?> GetObservable(this AvaloniaObject o, AvaloniaProperty property)
         {
             return new AvaloniaPropertyObservable<object?>(
                 o ?? throw new ArgumentNullException(nameof(o)), 
@@ -56,7 +56,7 @@ namespace Avalonia
         /// <remarks>
         /// The subscription to <paramref name="o"/> is created using a weak reference.
         /// </remarks>
-        public static IObservable<T> GetObservable<T>(this IAvaloniaObject o, AvaloniaProperty<T> property)
+        public static IObservable<T> GetObservable<T>(this AvaloniaObject o, AvaloniaProperty<T> property)
         {
             return new AvaloniaPropertyObservable<T>(
                 o ?? throw new ArgumentNullException(nameof(o)),
@@ -76,7 +76,7 @@ namespace Avalonia
         /// The subscription to <paramref name="o"/> is created using a weak reference.
         /// </remarks>
         public static IObservable<BindingValue<object?>> GetBindingObservable(
-            this IAvaloniaObject o,
+            this AvaloniaObject o,
             AvaloniaProperty property)
         {
             return new AvaloniaPropertyBindingObservable<object?>(
@@ -98,7 +98,7 @@ namespace Avalonia
         /// The subscription to <paramref name="o"/> is created using a weak reference.
         /// </remarks>
         public static IObservable<BindingValue<T>> GetBindingObservable<T>(
-            this IAvaloniaObject o,
+            this AvaloniaObject o,
             AvaloniaProperty<T> property)
         {
             return new AvaloniaPropertyBindingObservable<T>(
@@ -115,11 +115,11 @@ namespace Avalonia
         /// <param name="property">The property.</param>
         /// <returns>
         /// An observable which when subscribed pushes the property changed event args
-        /// each time a <see cref="IAvaloniaObject.PropertyChanged"/> event is raised
+        /// each time a <see cref="AvaloniaObject.PropertyChanged"/> event is raised
         /// for the specified property.
         /// </returns>
         public static IObservable<AvaloniaPropertyChangedEventArgs> GetPropertyChangedObservable(
-            this IAvaloniaObject o,
+            this AvaloniaObject o,
             AvaloniaProperty property)
         {
             return new AvaloniaPropertyChangedObservable(
@@ -140,7 +140,7 @@ namespace Avalonia
         /// property.
         /// </returns>
         public static ISubject<object?> GetSubject(
-            this IAvaloniaObject o,
+            this AvaloniaObject o,
             AvaloniaProperty property,
             BindingPriority priority = BindingPriority.LocalValue)
         {
@@ -163,7 +163,7 @@ namespace Avalonia
         /// property.
         /// </returns>
         public static ISubject<T> GetSubject<T>(
-            this IAvaloniaObject o,
+            this AvaloniaObject o,
             AvaloniaProperty<T> property,
             BindingPriority priority = BindingPriority.LocalValue)
         {
@@ -185,7 +185,7 @@ namespace Avalonia
         /// property.
         /// </returns>
         public static ISubject<BindingValue<object?>> GetBindingSubject(
-            this IAvaloniaObject o,
+            this AvaloniaObject o,
             AvaloniaProperty property,
             BindingPriority priority = BindingPriority.LocalValue)
         {
@@ -214,7 +214,7 @@ namespace Avalonia
         /// property.
         /// </returns>
         public static ISubject<BindingValue<T>> GetBindingSubject<T>(
-            this IAvaloniaObject o,
+            this AvaloniaObject o,
             AvaloniaProperty<T> property,
             BindingPriority priority = BindingPriority.LocalValue)
         {
@@ -241,7 +241,7 @@ namespace Avalonia
         /// A disposable which can be used to terminate the binding.
         /// </returns>
         public static IDisposable Bind<T>(
-            this IAvaloniaObject target,
+            this AvaloniaObject target,
             AvaloniaProperty<T> property,
             IObservable<BindingValue<T>> source,
             BindingPriority priority = BindingPriority.LocalValue)
@@ -250,17 +250,12 @@ namespace Avalonia
             property = property ?? throw new ArgumentNullException(nameof(property));
             source = source ?? throw new ArgumentNullException(nameof(source));
 
-            if (target is AvaloniaObject ao)
+            return property switch
             {
-                return property switch
-                {
-                    StyledPropertyBase<T> styled => ao.Bind(styled, source, priority),
-                    DirectPropertyBase<T> direct => ao.Bind(direct, source),
-                    _ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
-                };
-            }
-
-            throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
+                StyledPropertyBase<T> styled => target.Bind(styled, source, priority),
+                DirectPropertyBase<T> direct => target.Bind(direct, source),
+                _ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
+            };
         }
 
         /// <summary>
@@ -274,22 +269,17 @@ namespace Avalonia
         /// A disposable which can be used to terminate the binding.
         /// </returns>
         public static IDisposable Bind<T>(
-            this IAvaloniaObject target,
+            this AvaloniaObject target,
             AvaloniaProperty<T> property,
             IObservable<T> source,
             BindingPriority priority = BindingPriority.LocalValue)
         {
-            if (target is AvaloniaObject ao)
+            return property switch
             {
-                return property switch
-                {
-                    StyledPropertyBase<T> styled => ao.Bind(styled, source, priority),
-                    DirectPropertyBase<T> direct => ao.Bind(direct, source),
-                    _ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
-                };
-            }
-
-            throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
+                StyledPropertyBase<T> styled => target.Bind(styled, source, priority),
+                DirectPropertyBase<T> direct => target.Bind(direct, source),
+                _ => throw new NotSupportedException("Unsupported AvaloniaProperty type."),
+            };
         }
 
         /// <summary>
@@ -306,7 +296,7 @@ namespace Avalonia
         /// </param>
         /// <returns>An <see cref="IDisposable"/> which can be used to cancel the binding.</returns>
         public static IDisposable Bind(
-            this IAvaloniaObject target,
+            this AvaloniaObject target,
             AvaloniaProperty property,
             IBinding binding,
             object? anchor = null)
@@ -340,23 +330,17 @@ namespace Avalonia
         /// <param name="target">The object.</param>
         /// <param name="property">The property.</param>
         /// <returns>The value.</returns>
-        public static T GetValue<T>(this IAvaloniaObject target, AvaloniaProperty<T> property)
+        public static T GetValue<T>(this AvaloniaObject target, AvaloniaProperty<T> property)
         {
             target = target ?? throw new ArgumentNullException(nameof(target));
             property = property ?? throw new ArgumentNullException(nameof(property));
 
-            if (target is AvaloniaObject ao)
+            return property switch
             {
-                return property switch
-                {
-                    StyledPropertyBase<T> styled => ao.GetValue(styled),
-                    DirectPropertyBase<T> direct => ao.GetValue(direct),
-                    _ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
-                };
-
-            }
-
-            throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
+                StyledPropertyBase<T> styled => target.GetValue(styled),
+                DirectPropertyBase<T> direct => target.GetValue(direct),
+                _ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
+            };
         }
 
         /// <summary>
@@ -372,15 +356,13 @@ namespace Avalonia
         /// For direct properties returns the current value of the property.
         /// </remarks>
         public static object? GetBaseValue(
-            this IAvaloniaObject target,
+            this AvaloniaObject target,
             AvaloniaProperty property)
         {
             target = target ?? throw new ArgumentNullException(nameof(target));
             property = property ?? throw new ArgumentNullException(nameof(property));
 
-            if (target is AvaloniaObject ao)
-                return property.RouteGetBaseValue(ao);
-            throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
+            return property.RouteGetBaseValue(target);
         }
 
         /// <summary>
@@ -396,24 +378,18 @@ namespace Avalonia
         /// For direct properties returns the current value of the property.
         /// </remarks>
         public static Optional<T> GetBaseValue<T>(
-            this IAvaloniaObject target,
+            this AvaloniaObject target,
             AvaloniaProperty<T> property)
         {
             target = target ?? throw new ArgumentNullException(nameof(target));
             property = property ?? throw new ArgumentNullException(nameof(property));
 
-            if (target is AvaloniaObject ao)
+            return property switch
             {
-                return property switch
-                {
-                    StyledPropertyBase<T> styled => ao.GetBaseValue(styled),
-                    DirectPropertyBase<T> direct => ao.GetValue(direct),
-                    _ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
-                };
-
-            }
-
-            throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
+                StyledPropertyBase<T> styled => target.GetBaseValue(styled),
+                DirectPropertyBase<T> direct => target.GetValue(direct),
+                _ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
+            };
         }
 
         /// <summary>
@@ -474,7 +450,7 @@ namespace Avalonia
             }
 
             public InstancedBinding? Initiate(
-                IAvaloniaObject target,
+                AvaloniaObject target,
                 AvaloniaProperty? targetProperty,
                 object? anchor = null,
                 bool enableDataValidation = false)

+ 11 - 11
src/Avalonia.Base/AvaloniaProperty.cs

@@ -38,7 +38,7 @@ namespace Avalonia
             Type valueType,
             Type ownerType,
             AvaloniaPropertyMetadata metadata,
-            Action<IAvaloniaObject, bool>? notifying = null)
+            Action<AvaloniaObject, bool>? notifying = null)
         {
             _ = name ?? throw new ArgumentNullException(nameof(name));
 
@@ -145,7 +145,7 @@ namespace Avalonia
         /// will be true before the property change notifications are sent and false afterwards. This
         /// callback is intended to support Control.IsDataContextChanging.
         /// </remarks>
-        public Action<IAvaloniaObject, bool>? Notifying { get; }
+        public Action<AvaloniaObject, bool>? Notifying { get; }
 
         /// <summary>
         /// Gets the integer ID that represents this property.
@@ -238,9 +238,9 @@ namespace Avalonia
             bool inherits = false,
             BindingMode defaultBindingMode = BindingMode.OneWay,
             Func<TValue, bool>? validate = null,
-            Func<IAvaloniaObject, TValue, TValue>? coerce = null,
-            Action<IAvaloniaObject, bool>? notifying = null)
-                where TOwner : IAvaloniaObject
+            Func<AvaloniaObject, TValue, TValue>? coerce = null,
+            Action<AvaloniaObject, bool>? notifying = null)
+                where TOwner : AvaloniaObject
         {
             _ = name ?? throw new ArgumentNullException(nameof(name));
 
@@ -279,8 +279,8 @@ namespace Avalonia
             bool inherits = false,
             BindingMode defaultBindingMode = BindingMode.OneWay,
             Func<TValue, bool>? validate = null,
-            Func<IAvaloniaObject, TValue, TValue>? coerce = null)
-                where THost : IAvaloniaObject
+            Func<AvaloniaObject, TValue, TValue>? coerce = null)
+                where THost : AvaloniaObject
         {
             _ = name ?? throw new ArgumentNullException(nameof(name));
 
@@ -316,8 +316,8 @@ namespace Avalonia
             bool inherits = false,
             BindingMode defaultBindingMode = BindingMode.OneWay,
             Func<TValue, bool>? validate = null,
-            Func<IAvaloniaObject, TValue, TValue>? coerce = null)
-                where THost : IAvaloniaObject
+            Func<AvaloniaObject, TValue, TValue>? coerce = null)
+                where THost : AvaloniaObject
         {
             _ = name ?? throw new ArgumentNullException(nameof(name));
 
@@ -354,7 +354,7 @@ namespace Avalonia
             TValue unsetValue = default!,
             BindingMode defaultBindingMode = BindingMode.OneWay,
             bool enableDataValidation = false)
-                where TOwner : IAvaloniaObject
+                where TOwner : AvaloniaObject
         {
             _ = name ?? throw new ArgumentNullException(nameof(name));
             _ = getter ?? throw new ArgumentNullException(nameof(getter));
@@ -415,7 +415,7 @@ namespace Avalonia
         /// <returns>
         /// The property metadata.
         /// </returns>
-        public AvaloniaPropertyMetadata GetMetadata<T>() where T : IAvaloniaObject
+        public AvaloniaPropertyMetadata GetMetadata<T>() where T : AvaloniaObject
         {
             return GetMetadata(typeof(T));
         }

+ 3 - 3
src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs

@@ -9,7 +9,7 @@ namespace Avalonia
     public abstract class AvaloniaPropertyChangedEventArgs : EventArgs
     {
         public AvaloniaPropertyChangedEventArgs(
-            IAvaloniaObject sender,
+            AvaloniaObject sender,
             BindingPriority priority)
         {
             Sender = sender;
@@ -18,7 +18,7 @@ namespace Avalonia
         }
 
         internal AvaloniaPropertyChangedEventArgs(
-            IAvaloniaObject sender,
+            AvaloniaObject sender,
             BindingPriority priority,
             bool isEffectiveValueChange)
         {
@@ -31,7 +31,7 @@ namespace Avalonia
         /// Gets the <see cref="AvaloniaObject"/> that the property changed on.
         /// </summary>
         /// <value>The sender object.</value>
-        public IAvaloniaObject Sender { get; }
+        public AvaloniaObject Sender { get; }
 
         /// <summary>
         /// Gets the property that changed.

+ 2 - 2
src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs

@@ -16,7 +16,7 @@ namespace Avalonia
         /// <param name="newValue">The new value of the property.</param>
         /// <param name="priority">The priority of the binding that produced the value.</param>
         public AvaloniaPropertyChangedEventArgs(
-            IAvaloniaObject sender,
+            AvaloniaObject sender,
             AvaloniaProperty<T> property,
             Optional<T> oldValue,
             BindingValue<T> newValue,
@@ -26,7 +26,7 @@ namespace Avalonia
         }
 
         internal AvaloniaPropertyChangedEventArgs(
-            IAvaloniaObject sender,
+            AvaloniaObject sender,
             AvaloniaProperty<T> property,
             Optional<T> oldValue,
             BindingValue<T> newValue,

+ 6 - 6
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@@ -189,7 +189,7 @@ namespace Avalonia
         /// </summary>
         /// <param name="o">The object.</param>
         /// <returns>A collection of <see cref="AvaloniaProperty"/> definitions.</returns>
-        public IReadOnlyList<AvaloniaProperty> GetRegistered(IAvaloniaObject o)
+        public IReadOnlyList<AvaloniaProperty> GetRegistered(AvaloniaObject o)
         {
             _ = o ?? throw new ArgumentNullException(nameof(o));
 
@@ -205,7 +205,7 @@ namespace Avalonia
         /// The registered.
         /// </returns>
         public DirectPropertyBase<T> GetRegisteredDirect<T>(
-            IAvaloniaObject o,
+            AvaloniaObject o,
             DirectPropertyBase<T> property)
         {
             return FindRegisteredDirect(o, property) ??
@@ -260,7 +260,7 @@ namespace Avalonia
         /// <exception cref="InvalidOperationException">
         /// The property name contains a '.'.
         /// </exception>
-        public AvaloniaProperty? FindRegistered(IAvaloniaObject o, string name)
+        public AvaloniaProperty? FindRegistered(AvaloniaObject o, string name)
         {
             _ = o ?? throw new ArgumentNullException(nameof(o));
             _ = name ?? throw new ArgumentNullException(nameof(name));
@@ -277,7 +277,7 @@ namespace Avalonia
         /// The registered property or null if no matching property found.
         /// </returns>
         public DirectPropertyBase<T>? FindRegisteredDirect<T>(
-            IAvaloniaObject o,
+            AvaloniaObject o,
             DirectPropertyBase<T> property)
         {
             if (property.Owner == o.GetType())
@@ -362,7 +362,7 @@ namespace Avalonia
         /// <param name="property">The property.</param>
         /// <remarks>
         /// You won't usually want to call this method directly, instead use the
-        /// <see cref="AvaloniaProperty.Register{TOwner, TValue}(string, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{IAvaloniaObject, TValue, TValue}, Action{IAvaloniaObject, bool})"/>
+        /// <see cref="AvaloniaProperty.Register{TOwner, TValue}(string, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{AvaloniaObject, TValue, TValue}, Action{AvaloniaObject, bool})"/>
         /// method.
         /// </remarks>
         public void Register(Type type, AvaloniaProperty property)
@@ -413,7 +413,7 @@ namespace Avalonia
         /// <param name="property">The property.</param>
         /// <remarks>
         /// You won't usually want to call this method directly, instead use the
-        /// <see cref="AvaloniaProperty.RegisterAttached{THost, TValue}(string, Type, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{IAvaloniaObject, TValue, TValue})"/>
+        /// <see cref="AvaloniaProperty.RegisterAttached{THost, TValue}(string, Type, TValue, bool, Data.BindingMode, Func{TValue, bool}, Func{AvaloniaObject, TValue, TValue})"/>
         /// method.
         /// </remarks>
         public void RegisterAttached(Type type, AvaloniaProperty property)

+ 1 - 1
src/Avalonia.Base/AvaloniaProperty`1.cs

@@ -24,7 +24,7 @@ namespace Avalonia
             string name,
             Type ownerType,
             AvaloniaPropertyMetadata metadata,
-            Action<IAvaloniaObject, bool>? notifying = null)
+            Action<AvaloniaObject, bool>? notifying = null)
             : base(name, typeof(TValue), ownerType, metadata, notifying)
         {
             _changed = new Subject<AvaloniaPropertyChangedEventArgs<TValue>>();

+ 2 - 2
src/Avalonia.Base/ClassBindingManager.cs

@@ -9,7 +9,7 @@ namespace Avalonia
         private static readonly Dictionary<string, AvaloniaProperty> s_RegisteredProperties =
             new Dictionary<string, AvaloniaProperty>();
         
-        public static IDisposable Bind(IStyledElement target, string className, IBinding source, object anchor)
+        public static IDisposable Bind(StyledElement target, string className, IBinding source, object anchor)
         {
             if (!s_RegisteredProperties.TryGetValue(className, out var prop))
                 s_RegisteredProperties[className] = prop = RegisterClassProxyProperty(className);
@@ -21,7 +21,7 @@ namespace Avalonia
             var prop = AvaloniaProperty.Register<StyledElement, bool>("__AvaloniaReserved::Classes::" + className);
             prop.Changed.Subscribe(args =>
             {
-                var classes = ((IStyledElement)args.Sender).Classes;
+                var classes = ((StyledElement)args.Sender).Classes;
                 classes.Set(className, args.NewValue.GetValueOrDefault());
             });
             

+ 1 - 1
src/Avalonia.Base/Controls/Classes.cs

@@ -6,7 +6,7 @@ using Avalonia.Utilities;
 namespace Avalonia.Controls
 {
     /// <summary>
-    /// Holds a collection of style classes for an <see cref="IStyledElement"/>.
+    /// Holds a collection of style classes for an <see cref="StyledElement"/>.
     /// </summary>
     /// <remarks>
     /// Similar to CSS, each control may have any number of styling classes applied.

+ 1 - 1
src/Avalonia.Base/Controls/ISetInheritanceParent.cs

@@ -17,6 +17,6 @@ namespace Avalonia.Controls
         /// Sets the control's inheritance parent.
         /// </summary>
         /// <param name="parent">The parent.</param>
-        void SetParent(IAvaloniaObject? parent);
+        void SetParent(AvaloniaObject? parent);
     }
 }

+ 2 - 1
src/Avalonia.Base/Controls/ResourceNodeExtensions.cs

@@ -2,6 +2,7 @@
 using Avalonia.Data.Converters;
 using Avalonia.LogicalTree;
 using Avalonia.Reactive;
+using Avalonia.Styling;
 
 #nullable enable
 
@@ -49,7 +50,7 @@ namespace Avalonia.Controls
                     return true;
                 }
 
-                current = (current as IStyledElement)?.StylingParent as IResourceNode;
+                current = (current as IStyleHost)?.StylingParent as IResourceNode;
             }
 
             value = null;

+ 2 - 2
src/Avalonia.Base/Data/BindingOperations.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Data
         public static readonly object DoNothing = new DoNothingType();
 
         /// <summary>
-        /// Applies an <see cref="InstancedBinding"/> a property on an <see cref="IAvaloniaObject"/>.
+        /// Applies an <see cref="InstancedBinding"/> a property on an <see cref="AvaloniaObject"/>.
         /// </summary>
         /// <param name="target">The target object.</param>
         /// <param name="property">The property to bind.</param>
@@ -22,7 +22,7 @@ namespace Avalonia.Data
         /// </param>
         /// <returns>An <see cref="IDisposable"/> which can be used to cancel the binding.</returns>
         public static IDisposable Apply(
-            IAvaloniaObject target,
+            AvaloniaObject target,
             AvaloniaProperty property,
             InstancedBinding binding,
             object? anchor)

+ 2 - 2
src/Avalonia.Base/Data/Core/AvaloniaPropertyAccessorNode.cs

@@ -24,7 +24,7 @@ namespace Avalonia.Data.Core
         {
             try
             {
-                if (Target.TryGetTarget(out var target) && target is IAvaloniaObject obj)
+                if (Target.TryGetTarget(out var target) && target is AvaloniaObject obj)
                 {
                     obj.SetValue(_property, value, priority);
                     return true;
@@ -39,7 +39,7 @@ namespace Avalonia.Data.Core
 
         protected override void StartListeningCore(WeakReference<object?> reference)
         {
-            if (reference.TryGetTarget(out var target) && target is IAvaloniaObject obj)
+            if (reference.TryGetTarget(out var target) && target is AvaloniaObject obj)
             {
                 _subscription = new AvaloniaPropertyObservable<object?>(obj, _property).Subscribe(ValueChanged);
             }

+ 1 - 1
src/Avalonia.Base/Data/IBinding.cs

@@ -24,7 +24,7 @@ namespace Avalonia.Data
         /// A <see cref="InstancedBinding"/> or null if the binding could not be resolved.
         /// </returns>
         InstancedBinding? Initiate(
-            IAvaloniaObject target, 
+            AvaloniaObject target, 
             AvaloniaProperty? targetProperty,
             object? anchor = null,
             bool enableDataValidation = false);

+ 3 - 3
src/Avalonia.Base/Data/IndexerBinding.cs

@@ -3,7 +3,7 @@
     public class IndexerBinding : IBinding
     {
         public IndexerBinding(
-            IAvaloniaObject source,
+            AvaloniaObject source,
             AvaloniaProperty property,
             BindingMode mode)
         {
@@ -12,12 +12,12 @@
             Mode = mode;
         }
 
-        private IAvaloniaObject Source { get; }
+        private AvaloniaObject Source { get; }
         public AvaloniaProperty Property { get; }
         private BindingMode Mode { get; }
 
         public InstancedBinding? Initiate(
-            IAvaloniaObject target,
+            AvaloniaObject target,
             AvaloniaProperty? targetProperty,
             object? anchor = null,
             bool enableDataValidation = false)

+ 1 - 1
src/Avalonia.Base/Data/InstancedBinding.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Data
     /// <remarks>
     /// Whereas an <see cref="IBinding"/> holds a description of a binding such as "Bind to the X
     /// property on a control's DataContext"; this class represents a binding that has been 
-    /// *instanced* by calling <see cref="IBinding.Initiate(IAvaloniaObject, AvaloniaProperty, object, bool)"/>
+    /// *instanced* by calling <see cref="IBinding.Initiate(AvaloniaObject, AvaloniaProperty, object, bool)"/>
     /// on a target object.
     /// </remarks>
     public class InstancedBinding

+ 1 - 1
src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs

@@ -8,7 +8,7 @@ namespace Avalonia.Diagnostics
     public interface IAvaloniaObjectDebug
     {
         /// <summary>
-        /// Gets the subscriber list for the <see cref="IAvaloniaObject.PropertyChanged"/>
+        /// Gets the subscriber list for the <see cref="AvaloniaObject.PropertyChanged"/>
         /// event.
         /// </summary>
         /// <returns>

+ 5 - 5
src/Avalonia.Base/DirectProperty.cs

@@ -15,7 +15,7 @@ namespace Avalonia
     /// allows the avalonia property system to read and write the current value.
     /// </remarks>
     public class DirectProperty<TOwner, TValue> : DirectPropertyBase<TValue>, IDirectPropertyAccessor
-        where TOwner : IAvaloniaObject
+        where TOwner : AvaloniaObject
     {
         /// <summary>
         /// Initializes a new instance of the <see cref="DirectProperty{TOwner, TValue}"/> class.
@@ -151,13 +151,13 @@ namespace Avalonia
         }
 
         /// <inheritdoc/>
-        internal override TValue InvokeGetter(IAvaloniaObject instance)
+        internal override TValue InvokeGetter(AvaloniaObject instance)
         {
             return Getter((TOwner)instance);
         }
 
         /// <inheritdoc/>
-        internal override void InvokeSetter(IAvaloniaObject instance, BindingValue<TValue> value)
+        internal override void InvokeSetter(AvaloniaObject instance, BindingValue<TValue> value)
         {
             if (Setter == null)
             {
@@ -171,13 +171,13 @@ namespace Avalonia
         }
 
         /// <inheritdoc/>
-        object? IDirectPropertyAccessor.GetValue(IAvaloniaObject instance)
+        object? IDirectPropertyAccessor.GetValue(AvaloniaObject instance)
         {
             return Getter((TOwner)instance);
         }
 
         /// <inheritdoc/>
-        void IDirectPropertyAccessor.SetValue(IAvaloniaObject instance, object? value)
+        void IDirectPropertyAccessor.SetValue(AvaloniaObject instance, object? value)
         {
             if (Setter == null)
             {

+ 3 - 3
src/Avalonia.Base/DirectPropertyBase.cs

@@ -54,14 +54,14 @@ namespace Avalonia
         /// </summary>
         /// <param name="instance">The instance.</param>
         /// <returns>The property value.</returns>
-        internal abstract TValue InvokeGetter(IAvaloniaObject instance);
+        internal abstract TValue InvokeGetter(AvaloniaObject instance);
 
         /// <summary>
         /// Sets the value of the property on the instance.
         /// </summary>
         /// <param name="instance">The instance.</param>
         /// <param name="value">The value.</param>
-        internal abstract void InvokeSetter(IAvaloniaObject instance, BindingValue<TValue> value);
+        internal abstract void InvokeSetter(AvaloniaObject instance, BindingValue<TValue> value);
 
         /// <summary>
         /// Gets the unset value for the property on the specified type.
@@ -91,7 +91,7 @@ namespace Avalonia
         /// </summary>
         /// <typeparam name="T">The type.</typeparam>
         /// <param name="metadata">The metadata.</param>
-        public void OverrideMetadata<T>(DirectPropertyMetadata<TValue> metadata) where T : IAvaloniaObject
+        public void OverrideMetadata<T>(DirectPropertyMetadata<TValue> metadata) where T : AvaloniaObject
         {
             base.OverrideMetadata(typeof(T), metadata);
         }

+ 0 - 79
src/Avalonia.Base/IAvaloniaObject.cs

@@ -1,79 +0,0 @@
-using System;
-using Avalonia.Data;
-using Avalonia.Metadata;
-
-namespace Avalonia
-{
-    /// <summary>
-    /// Interface for getting/setting <see cref="AvaloniaProperty"/> values on an object.
-    /// </summary>
-    [NotClientImplementable]
-    public interface IAvaloniaObject
-    {
-        /// <summary>
-        /// Raised when a <see cref="AvaloniaProperty"/> value changes on this object.
-        /// </summary>
-        event EventHandler<AvaloniaPropertyChangedEventArgs>? PropertyChanged;
-
-        /// <summary>
-        /// Clears an <see cref="AvaloniaProperty"/>'s local value.
-        /// </summary>
-        /// <param name="property">The property.</param>
-        void ClearValue(AvaloniaProperty property);
-
-        /// <summary>
-        /// Gets a <see cref="AvaloniaProperty"/> value.
-        /// </summary>
-        /// <param name="property">The property.</param>
-        /// <returns>The value.</returns>
-        object? GetValue(AvaloniaProperty property);
-
-        /// <summary>
-        /// Checks whether a <see cref="AvaloniaProperty"/> is animating.
-        /// </summary>
-        /// <param name="property">The property.</param>
-        /// <returns>True if the property is animating, otherwise false.</returns>
-        bool IsAnimating(AvaloniaProperty property);
-
-        /// <summary>
-        /// Checks whether a <see cref="AvaloniaProperty"/> is set on this object.
-        /// </summary>
-        /// <param name="property">The property.</param>
-        /// <returns>True if the property is set, otherwise false.</returns>
-        bool IsSet(AvaloniaProperty property);
-
-        /// <summary>
-        /// Sets a <see cref="AvaloniaProperty"/> value.
-        /// </summary>
-        /// <param name="property">The property.</param>
-        /// <param name="value">The value.</param>
-        /// <param name="priority">The priority of the value.</param>
-        /// <returns>
-        /// An <see cref="IDisposable"/> if setting the property can be undone, otherwise null.
-        /// </returns>
-        IDisposable? SetValue(
-            AvaloniaProperty property,
-            object? value,
-            BindingPriority priority = BindingPriority.LocalValue);
-
-        /// <summary>
-        /// Binds a <see cref="AvaloniaProperty"/> to an observable.
-        /// </summary>
-        /// <param name="property">The property.</param>
-        /// <param name="source">The observable.</param>
-        /// <param name="priority">The priority of the binding.</param>
-        /// <returns>
-        /// A disposable which can be used to terminate the binding.
-        /// </returns>
-        IDisposable Bind(
-            AvaloniaProperty property,
-            IObservable<object?> source,
-            BindingPriority priority = BindingPriority.LocalValue);
-
-        /// <summary>
-        /// Coerces the specified <see cref="AvaloniaProperty"/>.
-        /// </summary>
-        /// <param name="property">The property.</param>
-        void CoerceValue(AvaloniaProperty property);
-    }
-}

+ 1 - 1
src/Avalonia.Base/IDataContextProvider.cs

@@ -6,7 +6,7 @@ namespace Avalonia
     /// Defines an element with a data context that can be used for binding.
     /// </summary>
     [NotClientImplementable]
-    public interface IDataContextProvider : IAvaloniaObject
+    public interface IDataContextProvider
     {
         /// <summary>
         /// Gets or sets the element's data context.

+ 2 - 2
src/Avalonia.Base/IDirectPropertyAccessor.cs

@@ -24,13 +24,13 @@ namespace Avalonia
         /// </summary>
         /// <param name="instance">The instance.</param>
         /// <returns>The property value.</returns>
-        object? GetValue(IAvaloniaObject instance);
+        object? GetValue(AvaloniaObject instance);
 
         /// <summary>
         /// Sets the value of the property on the instance.
         /// </summary>
         /// <param name="instance">The instance.</param>
         /// <param name="value">The value.</param>
-        void SetValue(IAvaloniaObject instance, object? value);
+        void SetValue(AvaloniaObject instance, object? value);
     }
 }

+ 0 - 39
src/Avalonia.Base/IStyledElement.cs

@@ -1,39 +0,0 @@
-using System;
-using System.ComponentModel;
-using Avalonia.Controls;
-using Avalonia.LogicalTree;
-using Avalonia.Metadata;
-using Avalonia.Styling;
-
-namespace Avalonia
-{
-    [NotClientImplementable]
-    public interface IStyledElement :
-        IStyleable,
-        IStyleHost,
-        ILogical,
-        IResourceHost,
-        IDataContextProvider,
-        ISupportInitialize
-    {
-        /// <summary>
-        /// Occurs when the control has finished initialization.
-        /// </summary>
-        event EventHandler? Initialized;
-
-        /// <summary>
-        /// Gets a value that indicates whether the element has finished initialization.
-        /// </summary>
-        bool IsInitialized { get; }
-
-        /// <summary>
-        /// Gets or sets the control's styling classes.
-        /// </summary>
-        new Classes Classes { get; set; }
-
-        /// <summary>
-        /// Gets the control's logical parent.
-        /// </summary>
-        IStyledElement? Parent { get; }
-    }
-}

+ 2 - 2
src/Avalonia.Base/Input/AccessKeyHandler.cs

@@ -182,13 +182,13 @@ namespace Avalonia.Input
                 // find all controls who have registered that access key.
                 var text = e.Key.ToString().ToUpper();
                 var matches = _registered
-                    .Where(x => x.Item1 == text && x.Item2.IsEffectivelyVisible)
+                    .Where(x => x.Item1 == text && ((Visual)x.Item2).IsEffectivelyVisible)
                     .Select(x => x.Item2);
 
                 // If the menu is open, only match controls in the menu's visual tree.
                 if (menuIsOpen)
                 {
-                    matches = matches.Where(x => x is not null && MainMenu!.IsVisualAncestorOf(x));
+                    matches = matches.Where(x => x is not null && ((Visual)MainMenu!).IsVisualAncestorOf((Visual)x));
                 }
 
                 var match = matches.FirstOrDefault();

+ 3 - 2
src/Avalonia.Base/Input/DragDropDevice.cs

@@ -13,7 +13,8 @@ namespace Avalonia.Input
         
         private Interactive? GetTarget(IInputRoot root, Point local)
         {
-            var target = root.InputHitTest(local)?.GetSelfAndVisualAncestors()?.OfType<Interactive>()?.FirstOrDefault();
+            var hit = root.InputHitTest(local) as Visual;
+            var target = hit?.GetSelfAndVisualAncestors()?.OfType<Interactive>()?.FirstOrDefault();
             if (target != null && DragDrop.GetAllowDrop(target))
                 return target;
             return null;
@@ -24,7 +25,7 @@ namespace Avalonia.Input
             if (target == null)
                 return DragDropEffects.None;
 
-            var p = inputRoot.TranslatePoint(point, target);
+            var p = ((Visual)inputRoot).TranslatePoint(point, target);
 
             if (!p.HasValue)
                 return DragDropEffects.None;

+ 1 - 1
src/Avalonia.Base/Input/DragEventArgs.cs

@@ -15,7 +15,7 @@ namespace Avalonia.Input
 
         public KeyModifiers KeyModifiers { get; private set; }
 
-        public Point GetPosition(IVisual relativeTo)
+        public Point GetPosition(Visual relativeTo)
         {
             var point = new Point(0, 0);
 

+ 10 - 7
src/Avalonia.Base/Input/FocusManager.cs

@@ -185,7 +185,7 @@ namespace Avalonia.Input
         /// </summary>
         /// <param name="e">The element.</param>
         /// <returns>True if the element can be focused.</returns>
-        private static bool CanFocus(IInputElement e) => e.Focusable && e.IsEffectivelyEnabled && e.IsVisible;
+        private static bool CanFocus(IInputElement e) => e.Focusable && e.IsEffectivelyEnabled && IsVisible(e);
 
         /// <summary>
         /// Gets the focus scope ancestors of the specified control, traversing popups.
@@ -198,14 +198,15 @@ namespace Avalonia.Input
 
             while (c != null)
             {
-                var scope = c as IFocusScope;
-
-                if (scope != null && c.VisualRoot?.IsVisible == true)
+                if (c is IFocusScope scope &&
+                    c is Visual v &&
+                    v.VisualRoot is Visual root &&
+                    root.IsVisible)
                 {
                     yield return scope;
                 }
 
-                c = c.GetVisualParent<IInputElement>() ??
+                c = (c as Visual)?.GetVisualParent<IInputElement>() ??
                     ((c as IHostedVisualTreeRoot)?.Host as IInputElement);
             }
         }
@@ -221,11 +222,11 @@ namespace Avalonia.Input
                 return;
 
             var ev = (PointerPressedEventArgs)e;
-            var visual = (IVisual)sender;
+            var visual = (Visual)sender;
 
             if (sender == e.Source && ev.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
             {
-                IVisual? element = ev.Pointer?.Captured ?? e.Source as IInputElement;
+                Visual? element = ev.Pointer?.Captured as Visual ?? e.Source as Visual;
 
                 while (element != null)
                 {
@@ -240,5 +241,7 @@ namespace Avalonia.Input
                 }
             }
         }
+
+        private static bool IsVisible(IInputElement e) => (e as Visual)?.IsVisible ?? true;
     }
 }

+ 2 - 2
src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs

@@ -35,8 +35,8 @@ namespace Avalonia.Input.GestureRecognizers
             if (_inputElement is ILogical logicalParent && recognizer is ISetLogicalParent logical)
             {
                 logical.SetParent(logicalParent);
-                if (recognizer is IStyleable styleableRecognizer
-                    && _inputElement is IStyleable styleableParent)
+                if (recognizer is StyledElement styleableRecognizer
+                    && _inputElement is StyledElement styleableParent)
                     styleableRecognizer.Bind(StyledElement.TemplatedParentProperty,
                         styleableParent.GetObservable(StyledElement.TemplatedParentProperty));
             }

+ 2 - 2
src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs

@@ -72,7 +72,7 @@ namespace Avalonia.Input.GestureRecognizers
                 EndGesture();
                 _tracking = e.Pointer;
                 _gestureId = ScrollGestureEventArgs.GetNextFreeId();
-                _trackedRootPoint = e.GetPosition(_target);
+                _trackedRootPoint = e.GetPosition((Visual?)_target);
             }
         }
 
@@ -86,7 +86,7 @@ namespace Avalonia.Input.GestureRecognizers
         {
             if (e.Pointer == _tracking)
             {
-                var rootPoint = e.GetPosition(_target);
+                var rootPoint = e.GetPosition((Visual?)_target);
                 if (!_scrolling)
                 {
                     if (CanHorizontallyScroll && Math.Abs(_trackedRootPoint.X - rootPoint.X) > ScrollStartDistance)

+ 3 - 3
src/Avalonia.Base/Input/Gestures.cs

@@ -92,13 +92,13 @@ namespace Avalonia.Input
             if (ev.Route == RoutingStrategies.Bubble)
             {
                 var e = (PointerPressedEventArgs)ev;
-                var visual = (IVisual)ev.Source;
+                var visual = (Visual)ev.Source;
 
                 if (e.ClickCount % 2 == 1)
                 {
                     s_isDoubleTapped = false;
                     s_lastPress.SetTarget(ev.Source);
-                    s_lastPressPoint = e.GetPosition((IVisual)ev.Source);
+                    s_lastPressPoint = e.GetPosition((Visual)ev.Source);
                 }
                 else if (e.ClickCount % 2 == 0 && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
                 {
@@ -121,7 +121,7 @@ namespace Avalonia.Input
                     target == e.Source &&
                     e.InitialPressMouseButton is MouseButton.Left or MouseButton.Right)
                 {
-                    var point = e.GetCurrentPoint((IVisual)target);
+                    var point = e.GetCurrentPoint((Visual)target);
                     var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
                     var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4);
                     var tapRect = new Rect(s_lastPressPoint, new Size())

+ 7 - 2
src/Avalonia.Base/Input/IInputElement.cs

@@ -12,7 +12,7 @@ namespace Avalonia.Input
     /// Defines input-related functionality for a control.
     /// </summary>
     [NotClientImplementable]
-    public interface IInputElement : IInteractive, IVisual
+    public interface IInputElement : IInteractive
     {
         /// <summary>
         /// Occurs when the control receives focus.
@@ -93,7 +93,12 @@ namespace Avalonia.Input
         /// <see cref="IsEnabled"/> value of this control and its parent controls.
         /// </remarks>
         bool IsEffectivelyEnabled { get; }
-        
+
+        /// <summary>
+        /// Gets a value indicating whether this control and all its parents are visible.
+        /// </summary>
+        bool IsEffectivelyVisible { get; }
+
         /// <summary>
         /// Gets a value indicating whether keyboard focus is anywhere within the element or its visual tree child elements.
         /// </summary>

+ 1 - 1
src/Avalonia.Base/Input/IMainMenu.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Input
     /// Defines the interface for a window's main menu.
     /// </summary>
     [NotClientImplementable]
-    public interface IMainMenu : IVisual
+    public interface IMainMenu
     {
         /// <summary>
         /// Gets a value indicating whether the menu is open.

+ 9 - 8
src/Avalonia.Base/Input/InputExtensions.cs

@@ -12,7 +12,7 @@ namespace Avalonia.Input
     /// </summary>
     public static class InputExtensions
     {
-        private static readonly Func<IVisual, bool> s_hitTestDelegate = IsHitTestVisible;
+        private static readonly Func<Visual, bool> s_hitTestDelegate = IsHitTestVisible;
 
         /// <summary>
         /// Returns the active input elements at a point on an <see cref="IInputElement"/>.
@@ -26,7 +26,8 @@ namespace Avalonia.Input
         {
             element = element ?? throw new ArgumentNullException(nameof(element));
 
-            return element.GetVisualsAt(p, s_hitTestDelegate).Cast<IInputElement>();
+            return (element as Visual)?.GetVisualsAt(p, s_hitTestDelegate).Cast<IInputElement>() ??
+                Enumerable.Empty<IInputElement>();
         }
 
         /// <summary>
@@ -39,7 +40,7 @@ namespace Avalonia.Input
         {
             element = element ?? throw new ArgumentNullException(nameof(element));
 
-            return element.GetVisualAt(p, s_hitTestDelegate) as IInputElement;
+            return (element as Visual)?.GetVisualAt(p, s_hitTestDelegate) as IInputElement;
         }
 
         /// <summary>
@@ -55,22 +56,22 @@ namespace Avalonia.Input
         public static IInputElement? InputHitTest(
             this IInputElement element,
             Point p,
-            Func<IVisual, bool> filter)
+            Func<Visual, bool> filter)
         {
             element = element ?? throw new ArgumentNullException(nameof(element));
             filter = filter ?? throw new ArgumentNullException(nameof(filter));
 
-            return element.GetVisualAt(p, x => s_hitTestDelegate(x) && filter(x)) as IInputElement;
+            return (element as Visual)?.GetVisualAt(p, x => s_hitTestDelegate(x) && filter(x)) as IInputElement;
         }
 
-        private static bool IsHitTestVisible(IVisual visual)
+        private static bool IsHitTestVisible(Visual visual)
         {
             var element = visual as IInputElement;
             return element != null &&
-                   element.IsVisible &&
+                   visual.IsVisible &&
                    element.IsHitTestVisible &&
                    element.IsEffectivelyEnabled &&
-                   element.IsAttachedToVisualTree;
+                   visual.IsAttachedToVisualTree;
         }
     }
 }

+ 22 - 17
src/Avalonia.Base/Input/KeyboardDevice.cs

@@ -3,7 +3,6 @@ using System.Runtime.CompilerServices;
 using Avalonia.Input.Raw;
 using Avalonia.Input.TextInput;
 using Avalonia.Interactivity;
-using Avalonia.VisualTree;
 
 namespace Avalonia.Input
 {
@@ -37,18 +36,21 @@ namespace Avalonia.Input
                     ie.IsKeyboardFocusWithin = false;
                 }
 
-                el = (IInputElement?)el.VisualParent;
+                el = (IInputElement?)(el as Visual)?.VisualParent;
             }
         }
         
         private void ClearFocusWithin(IInputElement element, bool clearRoot)
         {
-            foreach (var visual in element.VisualChildren)
+            if (element is Visual v)
             {
-                if (visual is IInputElement el && el.IsKeyboardFocusWithin)
+                foreach (var visual in v.VisualChildren)
                 {
-                    ClearFocusWithin(el, true);
-                    break;
+                    if (visual is IInputElement el && el.IsKeyboardFocusWithin)
+                    {
+                        ClearFocusWithin(el, true);
+                        break;
+                    }
                 }
             }
             
@@ -81,7 +83,7 @@ namespace Avalonia.Input
                     break;
                 }
 
-                el = el.VisualParent as IInputElement;
+                el = (el as Visual)?.VisualParent as IInputElement;
             }
 
             el = oldElement;
@@ -100,18 +102,21 @@ namespace Avalonia.Input
                     ie.IsKeyboardFocusWithin = true;
                 }
 
-                el = el.VisualParent as IInputElement;
+                el = (el as Visual)?.VisualParent as IInputElement;
             }
         }
         
         private void ClearChildrenFocusWithin(IInputElement element, bool clearRoot)
         {
-            foreach (var visual in element.VisualChildren)
+            if (element is Visual v)
             {
-                if (visual is IInputElement el && el.IsKeyboardFocusWithin)
+                foreach (var visual in v.VisualChildren)
                 {
-                    ClearChildrenFocusWithin(el, true);
-                    break;
+                    if (visual is IInputElement el && el.IsKeyboardFocusWithin)
+                    {
+                        ClearChildrenFocusWithin(el, true);
+                        break;
+                    }
                 }
             }
             
@@ -131,8 +136,8 @@ namespace Avalonia.Input
                 var interactive = FocusedElement as IInteractive;
 
                 if (FocusedElement != null && 
-                    (!FocusedElement.IsAttachedToVisualTree ||
-                     _focusedRoot != element?.VisualRoot as IInputRoot) &&
+                    (!((Visual)FocusedElement).IsAttachedToVisualTree ||
+                     _focusedRoot != ((Visual?)element)?.VisualRoot as IInputRoot) &&
                     _focusedRoot != null)
                 {
                     ClearChildrenFocusWithin(_focusedRoot, true);
@@ -140,7 +145,7 @@ namespace Avalonia.Input
                 
                 SetIsFocusWithin(FocusedElement, element);
                 _focusedElement = element;
-                _focusedRoot = _focusedElement?.VisualRoot as IInputRoot;
+                _focusedRoot = ((Visual?)_focusedElement)?.VisualRoot as IInputRoot;
 
                 interactive?.RaiseEvent(new RoutedEventArgs
                 {
@@ -191,8 +196,8 @@ namespace Avalonia.Input
                             KeyModifiers = keyInput.Modifiers.ToKeyModifiers(),
                             Source = element,
                         };
-
-                        IVisual? currentHandler = element;
+                        
+                        var currentHandler = element as Visual;
                         while (currentHandler != null && !ev.Handled && keyInput.Type == RawKeyEventType.KeyDown)
                         {
                             var bindings = (currentHandler as IInputElement)?.KeyBindings;

+ 1 - 1
src/Avalonia.Base/Input/KeyboardNavigation.cs

@@ -68,7 +68,7 @@ namespace Avalonia.Input
         /// <param name="value">The tab index.</param>
         public static void SetTabIndex(IInputElement element, int value)
         {
-            ((IAvaloniaObject)element).SetValue(TabIndexProperty, value);
+            ((AvaloniaObject)element).SetValue(TabIndexProperty, value);
         }
 
         /// <summary>

+ 3 - 3
src/Avalonia.Base/Input/KeyboardNavigationHandler.cs

@@ -50,7 +50,7 @@ namespace Avalonia.Input
             element = element ?? throw new ArgumentNullException(nameof(element));
 
             // If there's a custom keyboard navigation handler as an ancestor, use that.
-            var custom = element.FindAncestorOfType<ICustomKeyboardNavigation>(true);
+            var custom = (element as Visual)?.FindAncestorOfType<ICustomKeyboardNavigation>(true);
             if (custom is object && HandlePreCustomNavigation(custom, element, direction, out var ce))
                 return ce;
 
@@ -156,9 +156,9 @@ namespace Avalonia.Input
             NavigationDirection direction,
             [NotNullWhen(true)] out IInputElement? result)
         {
-            if (newElement is object)
+            if (newElement is Visual v)
             {
-                var customHandler = newElement.FindAncestorOfType<ICustomKeyboardNavigation>(true);
+                var customHandler = v.FindAncestorOfType<ICustomKeyboardNavigation>(true);
 
                 if (customHandler is object)
                 {

+ 7 - 7
src/Avalonia.Base/Input/MouseDevice.cs

@@ -141,7 +141,7 @@ namespace Avalonia.Input
                     _lastClickRect = new Rect(p, new Size())
                         .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
                     _lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
-                    var e = new PointerPressedEventArgs(source, _pointer, root, p, timestamp, properties, inputModifiers, _clickCount);
+                    var e = new PointerPressedEventArgs(source, _pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount);
                     source.RaiseEvent(e);
                     return e.Handled;
                 }
@@ -161,7 +161,7 @@ namespace Avalonia.Input
 
             if (source is object)
             {
-                var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, _pointer, root,
+                var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, _pointer, (Visual)root,
                     p, timestamp, properties, inputModifiers, intermediatePoints);
 
                 source.RaiseEvent(e);
@@ -181,7 +181,7 @@ namespace Avalonia.Input
 
             if (source is not null)
             {
-                var e = new PointerReleasedEventArgs(source, _pointer, root, p, timestamp, props, inputModifiers,
+                var e = new PointerReleasedEventArgs(source, _pointer, (Visual)root, p, timestamp, props, inputModifiers,
                     _lastMouseDownButton);
 
                 source?.RaiseEvent(e);
@@ -204,7 +204,7 @@ namespace Avalonia.Input
 
             if (source is not null)
             {
-                var e = new PointerWheelEventArgs(source, _pointer, root, p, timestamp, props, inputModifiers, delta);
+                var e = new PointerWheelEventArgs(source, _pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
 
                 source?.RaiseEvent(e);
                 return e.Handled;
@@ -224,7 +224,7 @@ namespace Avalonia.Input
             if (source != null)
             {
                 var e = new PointerDeltaEventArgs(Gestures.PointerTouchPadGestureMagnifyEvent, source,
-                    _pointer, root, p, timestamp, props, inputModifiers, delta);
+                    _pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
 
                 source?.RaiseEvent(e);
                 return e.Handled;
@@ -244,7 +244,7 @@ namespace Avalonia.Input
             if (source != null)
             {
                 var e = new PointerDeltaEventArgs(Gestures.PointerTouchPadGestureRotateEvent, source,
-                    _pointer, root, p, timestamp, props, inputModifiers, delta);
+                    _pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
 
                 source?.RaiseEvent(e);
                 return e.Handled;
@@ -264,7 +264,7 @@ namespace Avalonia.Input
             if (source != null)
             {
                 var e = new PointerDeltaEventArgs(Gestures.PointerTouchPadGestureSwipeEvent, source, 
-                    _pointer, root, p, timestamp, props, inputModifiers, delta);
+                    _pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
 
                 source?.RaiseEvent(e);
                 return e.Handled;

+ 10 - 2
src/Avalonia.Base/Input/Navigation/FocusExtensions.cs

@@ -10,13 +10,21 @@ namespace Avalonia.Input.Navigation
         /// </summary>
         /// <param name="e">The element.</param>
         /// <returns>True if the element can be focused.</returns>
-        public static bool CanFocus(this IInputElement e) => e.Focusable && e.IsEffectivelyEnabled && e.IsVisible;
+        public static bool CanFocus(this IInputElement e)
+        {
+            var visible = (e as Visual)?.IsVisible ?? true;
+            return e.Focusable && e.IsEffectivelyEnabled && visible;
+        }
 
         /// <summary>
         /// Checks if descendants of the specified element can be focused.
         /// </summary>
         /// <param name="e">The element.</param>
         /// <returns>True if descendants of the element can be focused.</returns>
-        public static bool CanFocusDescendants(this IInputElement e) => e.IsEffectivelyEnabled && e.IsVisible;
+        public static bool CanFocusDescendants(this IInputElement e)
+        {
+            var visible = (e as Visual)?.IsVisible ?? true;
+            return e.IsEffectivelyEnabled && visible;
+        }
     }
 }

+ 10 - 8
src/Avalonia.Base/Input/Navigation/TabNavigation.cs

@@ -212,9 +212,10 @@ namespace Avalonia.Input.Navigation
                     if (!IsFocusScope(e))
                     {
                         // Verify if focusedElement is a visual descendant of e
-                        if (focusedElement is IVisual visualFocusedElement &&
+                        if (focusedElement is Visual visualFocusedElement &&
+                            e is Visual v &&
                             visualFocusedElement != e &&
-                            e.IsVisualAncestorOf(visualFocusedElement))
+                            v.IsVisualAncestorOf(visualFocusedElement))
                         {
                             return focusedElement;
                         }
@@ -236,7 +237,7 @@ namespace Avalonia.Input.Navigation
 
             if (uiElement is null || IsVisibleAndEnabled(uiElement))
             {
-                if (e is IVisual elementAsVisual)
+                if (e is Visual elementAsVisual)
                 {
                     var children = elementAsVisual.VisualChildren;
                     var count = children.Count;
@@ -272,7 +273,7 @@ namespace Avalonia.Input.Navigation
 
             if (uiElement == null || IsVisibleAndEnabled(uiElement))
             {
-                var elementAsVisual = e as IVisual;
+                var elementAsVisual = e as Visual;
 
                 if (elementAsVisual != null)
                 {
@@ -385,7 +386,7 @@ namespace Avalonia.Input.Navigation
 
         private static IInputElement? GetNextSibling(IInputElement e)
         {
-            if (GetParent(e) is IVisual parentAsVisual && e is IVisual elementAsVisual)
+            if (GetParent(e) is Visual parentAsVisual && e is Visual elementAsVisual)
             {
                 var children = parentAsVisual.VisualChildren;
                 var count = children.Count;
@@ -589,7 +590,7 @@ namespace Avalonia.Input.Navigation
 
         private static IInputElement? GetPreviousSibling(IInputElement e)
         {
-            if (GetParent(e) is IVisual parentAsVisual && e is IVisual elementAsVisual)
+            if (GetParent(e) is Visual parentAsVisual && e is Visual elementAsVisual)
             {
                 var children = parentAsVisual.VisualChildren;
                 var count = children.Count;
@@ -646,7 +647,7 @@ namespace Avalonia.Input.Navigation
         private static IInputElement? GetParent(IInputElement e)
         {
             // For Visual - go up the visual parent chain until we find Visual.
-            if (e is IVisual v)
+            if (e is Visual v)
                 return v.FindAncestorOfType<IInputElement>();
 
             // This will need to be implemented when we have non-visual input elements.
@@ -669,6 +670,7 @@ namespace Avalonia.Input.Navigation
         }
 
         private static bool IsTabStopOrGroup(IInputElement e) => IsTabStop(e) || IsGroup(e);
-        private static bool IsVisibleAndEnabled(IInputElement e) => e.IsVisible && e.IsEnabled;
+        private static bool IsVisible(IInputElement e) => (e as Visual)?.IsVisible ?? true;
+        private static bool IsVisibleAndEnabled(IInputElement e) => IsVisible(e) && e.IsEnabled;
     }
 }

+ 3 - 3
src/Avalonia.Base/Input/PenDevice.cs

@@ -91,7 +91,7 @@ namespace Avalonia.Input
                 _lastClickRect = new Rect(p, new Size())
                     .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
                 _lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
-                var e = new PointerPressedEventArgs(source, pointer, root, p, timestamp, properties, inputModifiers, _clickCount);
+                var e = new PointerPressedEventArgs(source, pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount);
                 source.RaiseEvent(e);
                 return e.Handled;
             }
@@ -108,7 +108,7 @@ namespace Avalonia.Input
 
             if (source is not null)
             {
-                var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, pointer, root,
+                var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, pointer, (Visual)root,
                     p, timestamp, properties, inputModifiers, intermediatePoints);
 
                 source.RaiseEvent(e);
@@ -126,7 +126,7 @@ namespace Avalonia.Input
 
             if (source is not null)
             {
-                var e = new PointerReleasedEventArgs(source, pointer, root, p, timestamp, properties, inputModifiers,
+                var e = new PointerReleasedEventArgs(source, pointer, (Visual)root, p, timestamp, properties, inputModifiers,
                     _lastMouseDownButton);
 
                 source?.RaiseEvent(e);

+ 10 - 10
src/Avalonia.Base/Input/Pointer.cs

@@ -21,10 +21,10 @@ namespace Avalonia.Input
 
         IInputElement? FindCommonParent(IInputElement? control1, IInputElement? control2)
         {
-            if (control1 == null || control2 == null)
+            if (control1 is not Visual c1 || control2 is not Visual c2)
                 return null;
-            var seen = new HashSet<IInputElement>(control1.GetSelfAndVisualAncestors().OfType<IInputElement>());
-            return control2.GetSelfAndVisualAncestors().OfType<IInputElement>().FirstOrDefault(seen.Contains);
+            var seen = new HashSet<IInputElement>(c1.GetSelfAndVisualAncestors().OfType<IInputElement>());
+            return c2.GetSelfAndVisualAncestors().OfType<IInputElement>().FirstOrDefault(seen.Contains);
         }
 
         protected virtual void PlatformCapture(IInputElement? element)
@@ -34,15 +34,15 @@ namespace Avalonia.Input
         
         public void Capture(IInputElement? control)
         {
-            if (Captured != null)
-                Captured.DetachedFromVisualTree -= OnCaptureDetached;
+            if (Captured is Visual v1)
+                v1.DetachedFromVisualTree -= OnCaptureDetached;
             var oldCapture = Captured;
             Captured = control;
             PlatformCapture(control);
-            if (oldCapture != null)
+            if (oldCapture is Visual v2)
             {
                 var commonParent = FindCommonParent(control, oldCapture);
-                foreach (var notifyTarget in oldCapture.GetSelfAndVisualAncestors().OfType<IInputElement>())
+                foreach (var notifyTarget in v2.GetSelfAndVisualAncestors().OfType<IInputElement>())
                 {
                     if (notifyTarget == commonParent)
                         break;
@@ -50,11 +50,11 @@ namespace Avalonia.Input
                 }
             }
 
-            if (Captured != null)
-                Captured.DetachedFromVisualTree += OnCaptureDetached;
+            if (Captured is Visual v3)
+                v3.DetachedFromVisualTree += OnCaptureDetached;
         }
 
-        IInputElement? GetNextCapture(IVisual parent)
+        IInputElement? GetNextCapture(Visual parent)
         {
             return parent as IInputElement ?? parent.FindAncestorOfType<IInputElement>();
         }

+ 1 - 1
src/Avalonia.Base/Input/PointerDeltaEventArgs.cs

@@ -8,7 +8,7 @@ namespace Avalonia.Input
         public Vector Delta { get; set; }
 
         internal PointerDeltaEventArgs(RoutedEvent routedEvent, IInteractive? source, 
-            IPointer pointer, IVisual rootVisual, Point rootVisualPosition, ulong timestamp,
+            IPointer pointer, Visual rootVisual, Point rootVisualPosition, ulong timestamp,
             PointerPointProperties properties, KeyModifiers modifiers, Vector delta) 
             : base(routedEvent, source, pointer, rootVisual, rootVisualPosition,
                 timestamp, properties, modifiers)

+ 9 - 9
src/Avalonia.Base/Input/PointerEventArgs.cs

@@ -8,7 +8,7 @@ namespace Avalonia.Input
 {
     public class PointerEventArgs : RoutedEventArgs
     {
-        private readonly IVisual? _rootVisual;
+        private readonly Visual? _rootVisual;
         private readonly Point _rootVisualPosition;
         private readonly PointerPointProperties _properties;
         private readonly Lazy<IReadOnlyList<RawPointerPoint>?>? _previousPoints;
@@ -16,7 +16,7 @@ namespace Avalonia.Input
         internal PointerEventArgs(RoutedEvent routedEvent,
             IInteractive? source,
             IPointer pointer,
-            IVisual? rootVisual, Point rootVisualPosition,
+            Visual? rootVisual, Point rootVisualPosition,
             ulong timestamp,
             PointerPointProperties properties,
             KeyModifiers modifiers)
@@ -34,7 +34,7 @@ namespace Avalonia.Input
         internal PointerEventArgs(RoutedEvent routedEvent,
             IInteractive? source,
             IPointer pointer,
-            IVisual? rootVisual, Point rootVisualPosition,
+            Visual? rootVisual, Point rootVisualPosition,
             ulong timestamp,
             PointerPointProperties properties,
             KeyModifiers modifiers,
@@ -59,7 +59,7 @@ namespace Avalonia.Input
         /// </summary>
         public KeyModifiers KeyModifiers { get; }
 
-        private Point GetPosition(Point pt, IVisual? relativeTo)
+        private Point GetPosition(Point pt, Visual? relativeTo)
         {
             if (_rootVisual == null)
                 return default;
@@ -74,14 +74,14 @@ namespace Avalonia.Input
         /// </summary>
         /// <param name="relativeTo">The control.</param>
         /// <returns>The pointer position in the control's coordinates.</returns>
-        public Point GetPosition(IVisual? relativeTo) => GetPosition(_rootVisualPosition, relativeTo);
+        public Point GetPosition(Visual? relativeTo) => GetPosition(_rootVisualPosition, relativeTo);
 
         /// <summary>
         /// Returns the PointerPoint associated with the current event
         /// </summary>
         /// <param name="relativeTo">The visual which coordinate system to use. Pass null for toplevel coordinate system</param>
         /// <returns></returns>
-        public PointerPoint GetCurrentPoint(IVisual? relativeTo)
+        public PointerPoint GetCurrentPoint(Visual? relativeTo)
             => new PointerPoint(Pointer, GetPosition(relativeTo), _properties);
 
         /// <summary>
@@ -89,7 +89,7 @@ namespace Avalonia.Input
         /// </summary>
         /// <param name="relativeTo">The visual which coordinate system to use. Pass null for toplevel coordinate system</param>
         /// <returns></returns>
-        public IReadOnlyList<PointerPoint> GetIntermediatePoints(IVisual? relativeTo)
+        public IReadOnlyList<PointerPoint> GetIntermediatePoints(Visual? relativeTo)
         {
             var previousPoints = _previousPoints?.Value;            
             if (previousPoints == null || previousPoints.Count == 0)
@@ -127,7 +127,7 @@ namespace Avalonia.Input
         internal PointerPressedEventArgs(
             IInteractive source,
             IPointer pointer,
-            IVisual rootVisual, Point rootVisualPosition,
+            Visual rootVisual, Point rootVisualPosition,
             ulong timestamp,
             PointerPointProperties properties,
             KeyModifiers modifiers,
@@ -145,7 +145,7 @@ namespace Avalonia.Input
     {
         internal PointerReleasedEventArgs(
             IInteractive source, IPointer pointer,
-            IVisual rootVisual, Point rootVisualPosition, ulong timestamp,
+            Visual rootVisual, Point rootVisualPosition, ulong timestamp,
             PointerPointProperties properties, KeyModifiers modifiers,
             MouseButton initialPressMouseButton)
             : base(InputElement.PointerReleasedEvent, source, pointer, rootVisual, rootVisualPosition,

+ 31 - 17
src/Avalonia.Base/Input/PointerOverPreProcessor.cs

@@ -44,7 +44,7 @@ namespace Avalonia.Input
                     && _lastPointer is (var lastPointer, var lastPosition))
                 {
                     _lastPointer = null;
-                    ClearPointerOver(lastPointer, args.Root, 0, args.Root.PointToClient(lastPosition),
+                    ClearPointerOver(lastPointer, args.Root, 0, PointToClient(args.Root, lastPosition),
                         new PointerPointProperties(args.InputModifiers, args.Type.ToUpdateKind()),
                         args.InputModifiers.ToKeyModifiers());
                 }
@@ -64,14 +64,14 @@ namespace Avalonia.Input
         {
             if (_lastPointer is (var pointer, var position))
             {
-                var clientPoint = _inputRoot.PointToClient(position);
+                var clientPoint = PointToClient(_inputRoot, position);
 
                 if (dirtyRect.Contains(clientPoint))
                 {
                     var element = pointer.Captured ?? _inputRoot.InputHitTest(clientPoint);
                     SetPointerOver(pointer, _inputRoot, element, 0, clientPoint, PointerPointProperties.None, KeyModifiers.None);
                 }
-                else if (!_inputRoot.Bounds.Contains(clientPoint))
+                else if (!((Visual)_inputRoot).Bounds.Contains(clientPoint))
                 {
                     ClearPointerOver(pointer, _inputRoot, 0, clientPoint, PointerPointProperties.None, KeyModifiers.None);
                 }
@@ -82,7 +82,7 @@ namespace Avalonia.Input
         {
             if (_lastPointer is (var pointer, var position))
             {
-                var clientPoint = _inputRoot.PointToClient(position);
+                var clientPoint = PointToClient(_inputRoot, position);
                 ClearPointerOver(pointer, _inputRoot, 0, clientPoint, PointerPointProperties.None, KeyModifiers.None);
             }
             _lastPointer = null;
@@ -101,10 +101,10 @@ namespace Avalonia.Input
             // Do not pass rootVisual, when we have unknown position,
             // so GetPosition won't return invalid values.
             var e = new PointerEventArgs(InputElement.PointerExitedEvent, element, pointer,
-                position.HasValue ? root : null, position.HasValue ? position.Value : default,
+                position.HasValue ? root as Visual : null, position.HasValue ? position.Value : default,
                 timestamp, properties, inputModifiers);
 
-            if (element != null && !element.IsAttachedToVisualTree)
+            if (element is Visual v && !v.IsAttachedToVisualTree)
             {
                 // element has been removed from visual tree so do top down cleanup
                 if (root.IsPointerOver)
@@ -117,7 +117,7 @@ namespace Avalonia.Input
                 e.Source = element;
                 e.Handled = false;
                 element.RaiseEvent(e);
-                element = (IInputElement?)element.VisualParent;
+                element = GetVisualParent(element);
             }
 
             root.PointerOverElement = null;
@@ -127,14 +127,18 @@ namespace Avalonia.Input
 
         private void ClearChildrenPointerOver(PointerEventArgs e, IInputElement element, bool clearRoot)
         {
-            foreach (IInputElement el in element.VisualChildren)
+            if (element is Visual v)
             {
-                if (el.IsPointerOver)
+                foreach (IInputElement el in v.VisualChildren)
                 {
-                    ClearChildrenPointerOver(e, el, true);
-                    break;
+                    if (el.IsPointerOver)
+                    {
+                        ClearChildrenPointerOver(e, el, true);
+                        break;
+                    }
                 }
             }
+            
             if (clearRoot)
             {
                 e.Source = element;
@@ -160,7 +164,7 @@ namespace Avalonia.Input
                 }
             }
 
-            _lastPointer = (pointer, root.PointToScreen(position));
+            _lastPointer = (pointer, ((Visual)root).PointToScreen(position));
         }
 
         private void SetPointerOverToElement(IPointer pointer, IInputRoot root, IInputElement element,
@@ -177,14 +181,14 @@ namespace Avalonia.Input
                     branch = el;
                     break;
                 }
-                el = (IInputElement?)el.VisualParent;
+                el = GetVisualParent(el);
             }
 
             el = root.PointerOverElement;
 
-            var e = new PointerEventArgs(InputElement.PointerExitedEvent, el, pointer, root, position,
+            var e = new PointerEventArgs(InputElement.PointerExitedEvent, el, pointer, (Visual)root, position,
                 timestamp, properties, inputModifiers);
-            if (el != null && branch != null && !el.IsAttachedToVisualTree)
+            if (el is Visual v && branch != null && !v.IsAttachedToVisualTree)
             {
                 ClearChildrenPointerOver(e, branch, false);
             }
@@ -194,7 +198,7 @@ namespace Avalonia.Input
                 e.Source = el;
                 e.Handled = false;
                 el.RaiseEvent(e);
-                el = (IInputElement?)el.VisualParent;
+                el = GetVisualParent(el);
             }
 
             el = root.PointerOverElement = element;
@@ -206,8 +210,18 @@ namespace Avalonia.Input
                 e.Source = el;
                 e.Handled = false;
                 el.RaiseEvent(e);
-                el = (IInputElement?)el.VisualParent;
+                el = GetVisualParent(el);
             }
         }
+
+        private static IInputElement? GetVisualParent(IInputElement e)
+        {
+            return (e as Visual)?.VisualParent as IInputElement;
+        }
+
+        private static Point PointToClient(IInputRoot root, PixelPoint p)
+        {
+            return ((Visual)root).PointToClient(p);
+        }
     }
 }

+ 1 - 1
src/Avalonia.Base/Input/PointerWheelEventArgs.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Input
     {
         public Vector Delta { get; set; }
 
-        internal PointerWheelEventArgs(IInteractive source, IPointer pointer, IVisual rootVisual,
+        internal PointerWheelEventArgs(IInteractive source, IPointer pointer, Visual rootVisual,
             Point rootVisualPosition, ulong timestamp,
             PointerPointProperties properties, KeyModifiers modifiers, Vector delta)
             : base(InputElement.PointerWheelChangedEvent, source, pointer, rootVisual, rootVisualPosition,

+ 1 - 1
src/Avalonia.Base/Input/TappedEventArgs.cs

@@ -17,6 +17,6 @@ namespace Avalonia.Input
         public KeyModifiers KeyModifiers => lastPointerEventArgs.KeyModifiers;
         public ulong Timestamp => lastPointerEventArgs.Timestamp;
         
-        public Point GetPosition(IVisual? relativeTo) => lastPointerEventArgs.GetPosition(relativeTo);
+        public Point GetPosition(Visual? relativeTo) => lastPointerEventArgs.GetPosition(relativeTo);
     }
 }

+ 1 - 1
src/Avalonia.Base/Input/TextInput/ITextInputMethodClient.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Input.TextInput
         /// <summary>
         /// The visual that's showing the text
         /// </summary>
-        IVisual TextViewVisual { get; }
+        Visual TextViewVisual { get; }
         /// <summary>
         /// Should be fired when text-hosting visual is changed
         /// </summary>

+ 6 - 3
src/Avalonia.Base/Input/TextInput/InputMethodManager.cs

@@ -73,10 +73,13 @@ namespace Avalonia.Input.TextInput
 
         private void UpdateCursorRect()
         {
-            if (_im == null || _client == null || _focusedElement?.VisualRoot == null)
+            if (_im == null || 
+                _client == null || 
+                _focusedElement is not Visual v || 
+                v.VisualRoot is not Visual root)
                 return;
 
-            var transform = _focusedElement.TransformToVisual(_focusedElement.VisualRoot);
+            var transform = v.TransformToVisual(root);
             if (transform == null)
                 _im.SetCursorRect(default);
             else
@@ -95,7 +98,7 @@ namespace Avalonia.Input.TextInput
                 return;
             _focusedElement = element;
 
-            var inputMethod = (element?.VisualRoot as ITextInputMethodRoot)?.InputMethod;
+            var inputMethod = ((element as Visual)?.VisualRoot as ITextInputMethodRoot)?.InputMethod;
 
             if (_im != inputMethod)
             {

+ 3 - 3
src/Avalonia.Base/Input/TextInput/TransformTrackingHelper.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Input.TextInput
 {
     class TransformTrackingHelper : IDisposable
     {
-        private IVisual? _visual;
+        private Visual? _visual;
         private bool _queuedForUpdate;
         private readonly EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChangedHandler;
         private readonly List<Visual> _propertyChangedSubscriptions = new List<Visual>();
@@ -17,7 +17,7 @@ namespace Avalonia.Input.TextInput
             _propertyChangedHandler = PropertyChangedHandler;
         }
 
-        public void SetVisual(IVisual? visual)
+        public void SetVisual(Visual? visual)
         {
             Dispose();
             _visual = visual;
@@ -72,7 +72,7 @@ namespace Avalonia.Input.TextInput
         {
             Matrix? matrix = null;
             if (_visual != null && _visual.VisualRoot != null)
-                matrix = _visual.TransformToVisual(_visual.VisualRoot);
+                matrix = _visual.TransformToVisual((Visual)_visual.VisualRoot);
             if (Matrix != matrix)
             {
                 Matrix = matrix;

+ 3 - 3
src/Avalonia.Base/Input/TouchDevice.cs

@@ -75,7 +75,7 @@ namespace Avalonia.Input
                 }
 
                 target.RaiseEvent(new PointerPressedEventArgs(target, pointer,
-                    args.Root, args.Position, ev.Timestamp,
+                    (Visual)args.Root, args.Position, ev.Timestamp,
                     new PointerPointProperties(GetModifiers(args.InputModifiers, true), updateKind),
                     keyModifier, _clickCount));
             }
@@ -86,7 +86,7 @@ namespace Avalonia.Input
                 using (pointer)
                 {
                     target.RaiseEvent(new PointerReleasedEventArgs(target, pointer,
-                        args.Root, args.Position, ev.Timestamp,
+                        (Visual)args.Root, args.Position, ev.Timestamp,
                         new PointerPointProperties(GetModifiers(args.InputModifiers, false), updateKind),
                         keyModifier, MouseButton.Left));
                 }
@@ -101,7 +101,7 @@ namespace Avalonia.Input
 
             if (args.Type == RawPointerEventType.TouchUpdate)
             {
-                target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, target, pointer, args.Root,
+                target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, target, pointer, (Visual)args.Root,
                     args.Position, ev.Timestamp,
                     new PointerPointProperties(GetModifiers(args.InputModifiers, true), updateKind),
                     keyModifier, args.IntermediatePoints));

+ 1 - 1
src/Avalonia.Base/Interactivity/Interactive.cs

@@ -17,7 +17,7 @@ namespace Avalonia.Interactivity
         /// <summary>
         /// Gets the interactive parent of the object for bubbling and tunneling events.
         /// </summary>
-        IInteractive? IInteractive.InteractiveParent => ((IVisual)this).VisualParent as IInteractive;
+        IInteractive? IInteractive.InteractiveParent => this.VisualParent as IInteractive;
 
         /// <summary>
         /// Adds a handler for the specified routed event.

+ 1 - 1
src/Avalonia.Base/Layout/AttachedLayout.cs

@@ -43,7 +43,7 @@ namespace Avalonia.Layout
 
         /// <summary>
         /// Initializes any per-container state the layout requires when it is attached to an
-        /// <see cref="ILayoutable"/> container.
+        /// <see cref="Layoutable"/> container.
         /// </summary>
         /// <param name="context">
         /// The context object that facilitates communication between the layout and its host

+ 7 - 7
src/Avalonia.Base/Layout/ElementManager.cs

@@ -13,7 +13,7 @@ namespace Avalonia.Layout
 {
     internal class ElementManager
     {
-        private readonly List<ILayoutable?> _realizedElements = new List<ILayoutable?>();
+        private readonly List<Layoutable?> _realizedElements = new List<Layoutable?>();
         private readonly List<Rect> _realizedElementLayoutBounds = new List<Rect>();
         private int _firstRealizedDataIndex;
         private VirtualizingLayoutContext? _context;
@@ -69,9 +69,9 @@ namespace Avalonia.Layout
             return IsVirtualizingContext ? _realizedElements.Count : _context!.ItemCount;
         }
 
-        public ILayoutable GetAt(int realizedIndex)
+        public Layoutable GetAt(int realizedIndex)
         {
-            ILayoutable? element;
+            Layoutable? element;
 
             if (IsVirtualizingContext)
             {
@@ -99,7 +99,7 @@ namespace Avalonia.Layout
             return element;
         }
 
-        public void Add(ILayoutable element, int dataIndex)
+        public void Add(Layoutable element, int dataIndex)
         {
             if (_realizedElements.Count == 0)
             {
@@ -110,7 +110,7 @@ namespace Avalonia.Layout
             _realizedElementLayoutBounds.Add(default);
         }
 
-        public void Insert(int realizedIndex, int dataIndex, ILayoutable? element)
+        public void Insert(int realizedIndex, int dataIndex, Layoutable? element)
         {
             if (realizedIndex == 0)
             {
@@ -207,7 +207,7 @@ namespace Avalonia.Layout
 
         public bool IsIndexValidInData(int currentIndex) => (uint)currentIndex < _context!.ItemCount;
 
-        public ILayoutable? GetRealizedElement(int dataIndex)
+        public Layoutable? GetRealizedElement(int dataIndex)
         {
             return IsVirtualizingContext ?
                 GetAt(GetRealizedRangeIndexFromDataIndex(dataIndex)) :
@@ -330,7 +330,7 @@ namespace Avalonia.Layout
             }
         }
 
-        public int GetElementDataIndex(ILayoutable suggestedAnchor)
+        public int GetElementDataIndex(Layoutable suggestedAnchor)
         {
             var it = _realizedElements.IndexOf(suggestedAnchor);
             return it != -1 ? GetDataIndexFromRealizedRangeIndex(it) : -1;

+ 5 - 5
src/Avalonia.Base/Layout/FlowLayoutAlgorithm.cs

@@ -144,7 +144,7 @@ namespace Avalonia.Layout
         }
 
         public Size MeasureElement(
-            ILayoutable element,
+            Layoutable element,
             int index,
             Size availableSize,
             VirtualizingLayoutContext context)
@@ -512,9 +512,9 @@ namespace Avalonia.Layout
 
         private Rect EstimateExtent(Size availableSize, string? layoutId)
         {
-            ILayoutable? firstRealizedElement = null;
+            Layoutable? firstRealizedElement = null;
             Rect firstBounds = new Rect();
-            ILayoutable? lastRealizedElement = null;
+            Layoutable? lastRealizedElement = null;
             Rect lastBounds = new Rect();
             int firstDataIndex = -1;
             int lastDataIndex = -1;
@@ -727,7 +727,7 @@ namespace Avalonia.Layout
             }
         }
 
-        public ILayoutable? GetElementIfRealized(int dataIndex)
+        public Layoutable? GetElementIfRealized(int dataIndex)
         {
             if (_elementManager.IsDataIndexRealized(dataIndex))
             {
@@ -737,7 +737,7 @@ namespace Avalonia.Layout
             return null;
         }
 
-        public bool TryAddElement0(ILayoutable element)
+        public bool TryAddElement0(Layoutable element)
         {
             if (_elementManager.GetRealizedElementCount() == 0)
             {

+ 3 - 3
src/Avalonia.Base/Layout/IFlowLayoutAlgorithmDelegates.cs

@@ -21,14 +21,14 @@ namespace Avalonia.Layout
         Rect Algorithm_GetExtent(
             Size availableSize,
             VirtualizingLayoutContext context,
-            ILayoutable? firstRealized,
+            Layoutable? firstRealized,
             int firstRealizedItemIndex,
             Rect firstRealizedLayoutBounds,
-            ILayoutable? lastRealized,
+            Layoutable? lastRealized,
             int lastRealizedItemIndex,
             Rect lastRealizedLayoutBounds);
         void Algorithm_OnElementMeasured(
-            ILayoutable element,
+            Layoutable element,
             int index,
             Size availableSize,
             Size measureSize,

+ 4 - 4
src/Avalonia.Base/Layout/ILayoutManager.cs

@@ -18,13 +18,13 @@ namespace Avalonia.Layout
         /// Notifies the layout manager that a control requires a measure.
         /// </summary>
         /// <param name="control">The control.</param>
-        void InvalidateMeasure(ILayoutable control);
+        void InvalidateMeasure(Layoutable control);
 
         /// <summary>
         /// Notifies the layout manager that a control requires an arrange.
         /// </summary>
         /// <param name="control">The control.</param>
-        void InvalidateArrange(ILayoutable control);
+        void InvalidateArrange(Layoutable control);
 
         /// <summary>
         /// Executes a layout pass.
@@ -48,12 +48,12 @@ namespace Avalonia.Layout
         /// Registers a control as wanting to receive effective viewport notifications.
         /// </summary>
         /// <param name="control">The control.</param>
-        void RegisterEffectiveViewportListener(ILayoutable control);
+        void RegisterEffectiveViewportListener(Layoutable control);
 
         /// <summary>
         /// Registers a control as no longer wanting to receive effective viewport notifications.
         /// </summary>
         /// <param name="control">The control.</param>
-        void UnregisterEffectiveViewportListener(ILayoutable control);
+        void UnregisterEffectiveViewportListener(Layoutable control);
     }
 }

+ 1 - 1
src/Avalonia.Base/Layout/ILayoutRoot.cs

@@ -6,7 +6,7 @@ namespace Avalonia.Layout
     /// Defines the root of a layoutable tree.
     /// </summary>
     [NotClientImplementable]
-    public interface ILayoutRoot : ILayoutable
+    public interface ILayoutRoot
     {
         /// <summary>
         /// The size available to lay out the controls.

+ 0 - 122
src/Avalonia.Base/Layout/ILayoutable.cs

@@ -1,122 +0,0 @@
-using Avalonia.Metadata;
-using Avalonia.VisualTree;
-
-namespace Avalonia.Layout
-{
-    /// <summary>
-    /// Defines layout-related functionality for a control.
-    /// </summary>
-    [NotClientImplementable]
-    public interface ILayoutable : IVisual
-    {
-        /// <summary>
-        /// Gets the size that this element computed during the measure pass of the layout process.
-        /// </summary>
-        Size DesiredSize { get; }
-
-        /// <summary>
-        /// Gets the width of the element.
-        /// </summary>
-        double Width { get; }
-
-        /// <summary>
-        /// Gets the height of the element.
-        /// </summary>
-        double Height { get; }
-
-        /// <summary>
-        /// Gets the minimum width of the element.
-        /// </summary>
-        double MinWidth { get; }
-
-        /// <summary>
-        /// Gets the maximum width of the element.
-        /// </summary>
-        double MaxWidth { get; }
-
-        /// <summary>
-        /// Gets the minimum height of the element.
-        /// </summary>
-        double MinHeight { get; }
-
-        /// <summary>
-        /// Gets the maximum height of the element.
-        /// </summary>
-        double MaxHeight { get; }
-
-        /// <summary>
-        /// Gets the margin around the element.
-        /// </summary>
-        Thickness Margin { get; }
-
-        /// <summary>
-        /// Gets the element's preferred horizontal alignment in its parent.
-        /// </summary>
-        HorizontalAlignment HorizontalAlignment { get; }
-
-        /// <summary>
-        /// Gets the element's preferred vertical alignment in its parent.
-        /// </summary>
-        VerticalAlignment VerticalAlignment { get; }
-
-        /// <summary>
-        /// Gets a value indicating whether the control's layout measure is valid.
-        /// </summary>
-        bool IsMeasureValid { get; }
-
-        /// <summary>
-        /// Gets a value indicating whether the control's layouts arrange is valid.
-        /// </summary>
-        bool IsArrangeValid { get; }
-
-        /// <summary>
-        /// Gets the available size passed in the previous layout pass, if any.
-        /// </summary>
-        Size? PreviousMeasure { get; }
-
-        /// <summary>
-        /// Gets the layout rect passed in the previous layout pass, if any.
-        /// </summary>
-        Rect? PreviousArrange { get; }
-
-        /// <summary>
-        /// Creates the visual children of the control, if necessary
-        /// </summary>
-        void ApplyTemplate();
-
-        /// <summary>
-        /// Carries out a measure of the control.
-        /// </summary>
-        /// <param name="availableSize">The available size for the control.</param>
-        void Measure(Size availableSize);
-
-        /// <summary>
-        /// Arranges the control and its children.
-        /// </summary>
-        /// <param name="rect">The control's new bounds.</param>
-        void Arrange(Rect rect);
-
-        /// <summary>
-        /// Invalidates the measurement of the control and queues a new layout pass.
-        /// </summary>
-        void InvalidateMeasure();
-
-        /// <summary>
-        /// Invalidates the arrangement of the control and queues a new layout pass.
-        /// </summary>
-        void InvalidateArrange();
-
-        /// <summary>
-        /// Called when a child control's desired size changes.
-        /// </summary>
-        /// <param name="control">The child control.</param>
-        void ChildDesiredSizeChanged(ILayoutable control);
-
-        /// <summary>
-        /// Used by the <see cref="LayoutManager"/> to notify the control that its effective
-        /// viewport is changed.
-        /// </summary>
-        /// <param name="e">The viewport information.</param>
-        void EffectiveViewportChanged(EffectiveViewportChangedEventArgs e);
-    }
-}

+ 2 - 2
src/Avalonia.Base/Layout/LayoutContextAdapter.cs

@@ -38,8 +38,8 @@ namespace Avalonia.Layout
 
         protected override int ItemCountCore() => _nonVirtualizingContext.Children.Count;
         protected override object GetItemAtCore(int index) => _nonVirtualizingContext.Children[index];
-        protected override ILayoutable GetOrCreateElementAtCore(int index, ElementRealizationOptions options) =>
+        protected override Layoutable GetOrCreateElementAtCore(int index, ElementRealizationOptions options) =>
             _nonVirtualizingContext.Children[index];
-        protected override void RecycleElementCore(ILayoutable element) { }
+        protected override void RecycleElementCore(Layoutable element) { }
     }
 }

+ 22 - 21
src/Avalonia.Base/Layout/LayoutHelper.cs

@@ -16,15 +16,15 @@ namespace Avalonia.Layout
         public static double LayoutEpsilon { get; } = 0.00000153;
 
         /// <summary>
-        /// Calculates a control's size based on its <see cref="ILayoutable.Width"/>,
-        /// <see cref="ILayoutable.Height"/>, <see cref="ILayoutable.MinWidth"/>,
-        /// <see cref="ILayoutable.MaxWidth"/>, <see cref="ILayoutable.MinHeight"/> and
-        /// <see cref="ILayoutable.MaxHeight"/>.
+        /// Calculates a control's size based on its <see cref="Layoutable.Width"/>,
+        /// <see cref="Layoutable.Height"/>, <see cref="Layoutable.MinWidth"/>,
+        /// <see cref="Layoutable.MaxWidth"/>, <see cref="Layoutable.MinHeight"/> and
+        /// <see cref="Layoutable.MaxHeight"/>.
         /// </summary>
         /// <param name="control">The control.</param>
         /// <param name="constraints">The space available for the control.</param>
         /// <returns>The control's size.</returns>
-        public static Size ApplyLayoutConstraints(ILayoutable control, Size constraints)
+        public static Size ApplyLayoutConstraints(Layoutable control, Size constraints)
         {
             var minmax = new MinMax(control);
 
@@ -33,7 +33,7 @@ namespace Avalonia.Layout
                 MathUtilities.Clamp(constraints.Height, minmax.MinHeight, minmax.MaxHeight));
         }
 
-        public static Size MeasureChild(ILayoutable? control, Size availableSize, Thickness padding,
+        public static Size MeasureChild(Layoutable? control, Size availableSize, Thickness padding,
             Thickness borderThickness)
         {
             if (IsParentLayoutRounded(control, out double scale))
@@ -51,7 +51,7 @@ namespace Avalonia.Layout
             return new Size().Inflate(padding + borderThickness);
         }
 
-        public static Size MeasureChild(ILayoutable? control, Size availableSize, Thickness padding)
+        public static Size MeasureChild(Layoutable? control, Size availableSize, Thickness padding)
         {
             if (IsParentLayoutRounded(control, out double scale))
             {
@@ -67,7 +67,7 @@ namespace Avalonia.Layout
             return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
         }
 
-        public static Size ArrangeChild(ILayoutable? child, Size availableSize, Thickness padding, Thickness borderThickness)
+        public static Size ArrangeChild(Layoutable? child, Size availableSize, Thickness padding, Thickness borderThickness)
         {
             if (IsParentLayoutRounded(child, out double scale))
             {
@@ -78,7 +78,7 @@ namespace Avalonia.Layout
             return ArrangeChildInternal(child, availableSize, padding + borderThickness);
         }
 
-        public static Size ArrangeChild(ILayoutable? child, Size availableSize, Thickness padding)
+        public static Size ArrangeChild(Layoutable? child, Size availableSize, Thickness padding)
         {
             if(IsParentLayoutRounded(child, out double scale))
                 padding = RoundLayoutThickness(padding, scale, scale);
@@ -86,18 +86,18 @@ namespace Avalonia.Layout
             return ArrangeChildInternal(child, availableSize, padding);
         }
 
-        private static Size ArrangeChildInternal(ILayoutable? child, Size availableSize, Thickness padding)
+        private static Size ArrangeChildInternal(Layoutable? child, Size availableSize, Thickness padding)
         {
             child?.Arrange(new Rect(availableSize).Deflate(padding));
 
             return availableSize;
         }
 
-        private static bool IsParentLayoutRounded(ILayoutable? child, out double scale)
+        private static bool IsParentLayoutRounded(Layoutable? child, out double scale)
         {
-            var layoutableParent = (ILayoutable?)child?.GetVisualParent();
+            var layoutableParent = (child as Visual)?.GetVisualParent() as Layoutable;
 
-            if (layoutableParent == null || !((Layoutable)layoutableParent).UseLayoutRounding)
+            if (layoutableParent == null || !layoutableParent.UseLayoutRounding)
             {
                 scale = 1.0;
                 return false;
@@ -110,11 +110,11 @@ namespace Avalonia.Layout
         /// <summary>
         /// Invalidates measure for given control and all visual children recursively.
         /// </summary>
-        public static void InvalidateSelfAndChildrenMeasure(ILayoutable control)
+        public static void InvalidateSelfAndChildrenMeasure(Layoutable control)
         {
-            void InnerInvalidateMeasure(IVisual target)
+            void InnerInvalidateMeasure(Visual target)
             {
-                if (target is ILayoutable targetLayoutable)
+                if (target is Layoutable targetLayoutable)
                 {
                     targetLayoutable.InvalidateMeasure();
                 }
@@ -124,13 +124,14 @@ namespace Avalonia.Layout
 
                 for (int i = 0; i < visualChildrenCount; i++)
                 {
-                    IVisual child = visualChildren[i];
+                    Visual child = visualChildren[i];
 
                     InnerInvalidateMeasure(child);
                 }
             }
 
-            InnerInvalidateMeasure(control);
+            if (control is Visual v)
+                InnerInvalidateMeasure(v);
         }
 
         /// <summary>
@@ -138,9 +139,9 @@ namespace Avalonia.Layout
         /// </summary>
         /// <param name="control">The control.</param>
         /// <exception cref="Exception">Thrown when control has no root or returned layout scaling is invalid.</exception>
-        public static double GetLayoutScale(ILayoutable control)
+        public static double GetLayoutScale(Layoutable control)
         {
-            var visualRoot = control.VisualRoot;
+            var visualRoot = (control as Visual)?.VisualRoot;
             
             var result = (visualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;
 
@@ -289,7 +290,7 @@ namespace Avalonia.Layout
         /// </summary>
         private readonly struct MinMax
         {
-            public MinMax(ILayoutable e)
+            public MinMax(Layoutable e)
             {
                 MaxHeight = e.MaxHeight;
                 MinHeight = e.MinHeight;

+ 19 - 19
src/Avalonia.Base/Layout/LayoutManager.cs

@@ -16,9 +16,9 @@ namespace Avalonia.Layout
     public class LayoutManager : ILayoutManager, IDisposable
     {
         private const int MaxPasses = 3;
-        private readonly ILayoutRoot _owner;
-        private readonly LayoutQueue<ILayoutable> _toMeasure = new LayoutQueue<ILayoutable>(v => !v.IsMeasureValid);
-        private readonly LayoutQueue<ILayoutable> _toArrange = new LayoutQueue<ILayoutable>(v => !v.IsArrangeValid);
+        private readonly Layoutable _owner;
+        private readonly LayoutQueue<Layoutable> _toMeasure = new LayoutQueue<Layoutable>(v => !v.IsMeasureValid);
+        private readonly LayoutQueue<Layoutable> _toArrange = new LayoutQueue<Layoutable>(v => !v.IsArrangeValid);
         private readonly Action _executeLayoutPass;
         private List<EffectiveViewportChangedListener>? _effectiveViewportChangedListeners;
         private bool _disposed;
@@ -27,14 +27,14 @@ namespace Avalonia.Layout
 
         public LayoutManager(ILayoutRoot owner)
         {
-            _owner = owner ?? throw new ArgumentNullException(nameof(owner));
+            _owner = owner as Layoutable ?? throw new ArgumentNullException(nameof(owner));
             _executeLayoutPass = ExecuteQueuedLayoutPass;
         }
 
         public virtual event EventHandler? LayoutUpdated;
 
         /// <inheritdoc/>
-        public virtual void InvalidateMeasure(ILayoutable control)
+        public virtual void InvalidateMeasure(Layoutable control)
         {
             control = control ?? throw new ArgumentNullException(nameof(control));
             Dispatcher.UIThread.VerifyAccess();
@@ -65,7 +65,7 @@ namespace Avalonia.Layout
         }
 
         /// <inheritdoc/>
-        public virtual void InvalidateArrange(ILayoutable control)
+        public virtual void InvalidateArrange(Layoutable control)
         {
             control = control ?? throw new ArgumentNullException(nameof(control));
             Dispatcher.UIThread.VerifyAccess();
@@ -203,7 +203,7 @@ namespace Avalonia.Layout
             _toArrange.Dispose();
         }
 
-        void ILayoutManager.RegisterEffectiveViewportListener(ILayoutable control)
+        void ILayoutManager.RegisterEffectiveViewportListener(Layoutable control)
         {
             _effectiveViewportChangedListeners ??= new List<EffectiveViewportChangedListener>();
             _effectiveViewportChangedListeners.Add(new EffectiveViewportChangedListener(
@@ -211,7 +211,7 @@ namespace Avalonia.Layout
                 CalculateEffectiveViewport(control)));
         }
 
-        void ILayoutManager.UnregisterEffectiveViewportListener(ILayoutable control)
+        void ILayoutManager.UnregisterEffectiveViewportListener(Layoutable control)
         {
             if (_effectiveViewportChangedListeners is object)
             {
@@ -265,13 +265,13 @@ namespace Avalonia.Layout
             }
         }
 
-        private void Measure(ILayoutable control)
+        private void Measure(Layoutable control)
         {
             // Controls closest to the visual root need to be arranged first. We don't try to store
             // ordered invalidation lists, instead we traverse the tree upwards, measuring the
             // controls closest to the root first. This has been shown by benchmarks to be the
             // fastest and most memory-efficient algorithm.
-            if (control.VisualParent is ILayoutable parent)
+            if (control.VisualParent is Layoutable parent)
             {
                 Measure(parent);
             }
@@ -283,7 +283,7 @@ namespace Avalonia.Layout
             {
                 if (control is ILayoutRoot root)
                 {
-                    root.Measure(Size.Infinity);
+                    control.Measure(Size.Infinity);
                 }
                 else if (control.PreviousMeasure.HasValue)
                 {
@@ -292,9 +292,9 @@ namespace Avalonia.Layout
             }
         }
 
-        private void Arrange(ILayoutable control)
+        private void Arrange(Layoutable control)
         {
-            if (control.VisualParent is ILayoutable parent)
+            if (control.VisualParent is Layoutable parent)
             {
                 Arrange(parent);
             }
@@ -304,7 +304,7 @@ namespace Avalonia.Layout
                 if (control is IEmbeddedLayoutRoot embeddedRoot)
                     control.Arrange(new Rect(embeddedRoot.AllocatedSize));
                 else if (control is ILayoutRoot root)
-                    control.Arrange(new Rect(root.DesiredSize));
+                    control.Arrange(new Rect(control.DesiredSize));
                 else if (control.PreviousArrange != null)
                 {
                     // Has been observed that PreviousArrange sometimes is null, probably a bug somewhere else.
@@ -350,7 +350,7 @@ namespace Avalonia.Layout
 
                         if (viewport != l.Viewport)
                         {
-                            l.Listener.EffectiveViewportChanged(new EffectiveViewportChangedEventArgs(viewport));
+                            l.Listener.RaiseEffectiveViewportChanged(new EffectiveViewportChangedEventArgs(viewport));
                             l.Viewport = viewport;
                         }
                     }
@@ -364,14 +364,14 @@ namespace Avalonia.Layout
             return startCount != _toMeasure.Count + _toArrange.Count;
         }
 
-        private Rect CalculateEffectiveViewport(IVisual control)
+        private Rect CalculateEffectiveViewport(Visual control)
         {
             var viewport = new Rect(0, 0, double.PositiveInfinity, double.PositiveInfinity);
             CalculateEffectiveViewport(control, control, ref viewport);
             return viewport;
         }
 
-        private void CalculateEffectiveViewport(IVisual target, IVisual control, ref Rect viewport)
+        private void CalculateEffectiveViewport(Visual target, Visual control, ref Rect viewport)
         {
             // Recurse until the top level control.
             if (control.VisualParent is object)
@@ -405,13 +405,13 @@ namespace Avalonia.Layout
 
         private class EffectiveViewportChangedListener
         {
-            public EffectiveViewportChangedListener(ILayoutable listener, Rect viewport)
+            public EffectiveViewportChangedListener(Layoutable listener, Rect viewport)
             {
                 Listener = listener;
                 Viewport = viewport;
             }
 
-            public ILayoutable Listener { get; }
+            public Layoutable Listener { get; }
             public Rect Viewport { get; set; }
         }
     }

+ 16 - 19
src/Avalonia.Base/Layout/Layoutable.cs

@@ -62,7 +62,7 @@ namespace Avalonia.Layout
     /// <summary>
     /// Implements layout-related functionality for a control.
     /// </summary>
-    public class Layoutable : Visual, ILayoutable
+    public class Layoutable : Visual
     {
         /// <summary>
         /// Defines the <see cref="DesiredSize"/> property.
@@ -323,15 +323,12 @@ namespace Avalonia.Layout
             set { SetValue(UseLayoutRoundingProperty, value); }
         }
 
-        /// <summary>
-        /// Gets the available size passed in the previous layout pass, if any.
-        /// </summary>
-        Size? ILayoutable.PreviousMeasure => _previousMeasure;
+        internal Size? PreviousMeasure => _previousMeasure;
 
         /// <summary>
         /// Gets the layout rect passed in the previous layout pass, if any.
         /// </summary>
-        Rect? ILayoutable.PreviousArrange => _previousArrange;
+        internal Rect? PreviousArrange => _previousArrange;
 
         /// <summary>
         /// Creates the visual children of the control, if necessary
@@ -380,7 +377,7 @@ namespace Avalonia.Layout
 
                 if (DesiredSize != previousDesiredSize)
                 {
-                    this.GetVisualParent<ILayoutable>()?.ChildDesiredSizeChanged(this);
+                    this.GetVisualParent<Layoutable>()?.ChildDesiredSizeChanged(this);
                 }
             }
         }
@@ -423,7 +420,7 @@ namespace Avalonia.Layout
                 IsMeasureValid = false;
                 IsArrangeValid = false;
 
-                if (((ILayoutable)this).IsAttachedToVisualTree)
+                if (IsAttachedToVisualTree)
                 {
                     (VisualRoot as ILayoutRoot)?.LayoutManager.InvalidateMeasure(this);
                     InvalidateVisual();
@@ -448,7 +445,7 @@ namespace Avalonia.Layout
         }
 
         /// <inheritdoc/>
-        void ILayoutable.ChildDesiredSizeChanged(ILayoutable control)
+        internal void ChildDesiredSizeChanged(Layoutable control)
         {
             if (!_measuring)
             {
@@ -456,11 +453,11 @@ namespace Avalonia.Layout
             }
         }
 
-        void ILayoutable.EffectiveViewportChanged(EffectiveViewportChangedEventArgs e)
+        internal void RaiseEffectiveViewportChanged(EffectiveViewportChangedEventArgs e)
         {
             _effectiveViewportChanged?.Invoke(this, e);
         }
-
+        
         /// <summary>
         /// Marks a property as affecting the control's measurement.
         /// </summary>
@@ -471,7 +468,7 @@ namespace Avalonia.Layout
         /// property will cause <see cref="InvalidateMeasure"/> to be called on the element.
         /// </remarks>
         protected static void AffectsMeasure<T>(params AvaloniaProperty[] properties)
-            where T : class, ILayoutable
+            where T : Layoutable
         {
             void Invalidate(AvaloniaPropertyChangedEventArgs e)
             {
@@ -494,7 +491,7 @@ namespace Avalonia.Layout
         /// property will cause <see cref="InvalidateArrange"/> to be called on the element.
         /// </remarks>
         protected static void AffectsArrange<T>(params AvaloniaProperty[] properties)
-            where T : class, ILayoutable
+            where T : Layoutable
         {
             void Invalidate(AvaloniaPropertyChangedEventArgs e)
             {
@@ -596,9 +593,9 @@ namespace Avalonia.Layout
 
             for (var i = 0; i < visualCount; i++)
             {
-                IVisual visual = visualChildren[i];
+                Visual visual = visualChildren[i];
 
-                if (visual is ILayoutable layoutable)
+                if (visual is Layoutable layoutable)
                 {
                     layoutable.Measure(availableSize);
                     width = Math.Max(width, layoutable.DesiredSize.Width);
@@ -709,9 +706,9 @@ namespace Avalonia.Layout
 
             for (var i = 0; i < visualCount; i++)
             {
-                IVisual visual = visualChildren[i];
+                Visual visual = visualChildren[i];
 
-                if (visual is ILayoutable layoutable)
+                if (visual is Layoutable layoutable)
                 {
                     layoutable.Arrange(arrangeRect);
                 }
@@ -778,7 +775,7 @@ namespace Avalonia.Layout
                 DesiredSize = default;
 
                 // All changes to visibility cause the parent element to be notified.
-                this.GetVisualParent<ILayoutable>()?.ChildDesiredSizeChanged(this);
+                this.GetVisualParent<Layoutable>()?.ChildDesiredSizeChanged(this);
 
                 // We only invalidate outselves when visibility is changed to true.
                 if (change.GetNewValue<bool>())
@@ -789,7 +786,7 @@ namespace Avalonia.Layout
         }
 
         /// <inheritdoc/>
-        protected sealed override void OnVisualParentChanged(IVisual? oldParent, IVisual? newParent)
+        protected sealed override void OnVisualParentChanged(Visual? oldParent, Visual? newParent)
         {
             LayoutHelper.InvalidateSelfAndChildrenMeasure(this);
 

+ 2 - 2
src/Avalonia.Base/Layout/NonVirtualizingLayoutContext.cs

@@ -17,13 +17,13 @@ namespace Avalonia.Layout
         /// <summary>
         /// Gets the collection of child controls from the container that provides the context.
         /// </summary>
-        public IReadOnlyList<ILayoutable> Children => ChildrenCore;
+        public IReadOnlyList<Layoutable> Children => ChildrenCore;
 
         /// <summary>
         /// Implements the behavior for getting the return value of <see cref="Children"/> in a
         /// derived or custom <see cref="NonVirtualizingLayoutContext"/>.
         /// </summary>
-        protected abstract IReadOnlyList<ILayoutable> ChildrenCore { get; }
+        protected abstract IReadOnlyList<Layoutable> ChildrenCore { get; }
 
         internal VirtualizingLayoutContext GetVirtualizingContextAdapter() =>
             _contextAdapter ??= new LayoutContextAdapter(this);

+ 4 - 4
src/Avalonia.Base/Layout/NonVirtualizingStackLayout.cs

@@ -59,7 +59,7 @@ namespace Avalonia.Layout
             {
                 var element = context.Children[i];
 
-                if (!element.IsVisible)
+                if ((element as Visual)?.IsVisible == false)
                 {
                     continue;
                 }
@@ -100,7 +100,7 @@ namespace Avalonia.Layout
             {
                 var element = context.Children[i];
 
-                if (!element.IsVisible)
+                if ((element as Visual)?.IsVisible == false)
                 {
                     continue;
                 }
@@ -117,7 +117,7 @@ namespace Avalonia.Layout
                 Math.Max(finalSize.Height, bounds.Height));
         }
 
-        private static Rect LayoutVertical(ILayoutable element, double y, Size constraint)
+        private static Rect LayoutVertical(Layoutable element, double y, Size constraint)
         {
             var x = 0.0;
             var width = element.DesiredSize.Width;
@@ -138,7 +138,7 @@ namespace Avalonia.Layout
             return new Rect(x, y, width, element.DesiredSize.Height);
         }
 
-        private static Rect LayoutHorizontal(ILayoutable element, double x, Size constraint)
+        private static Rect LayoutHorizontal(Layoutable element, double x, Size constraint)
         {
             var y = 0.0;
             var height = element.DesiredSize.Height;

+ 6 - 6
src/Avalonia.Base/Layout/StackLayout.cs

@@ -78,10 +78,10 @@ namespace Avalonia.Layout
         internal Rect GetExtent(
             Size availableSize,
             VirtualizingLayoutContext context,
-            ILayoutable? firstRealized,
+            Layoutable? firstRealized,
             int firstRealizedItemIndex,
             Rect firstRealizedLayoutBounds,
-            ILayoutable? lastRealized,
+            Layoutable? lastRealized,
             int lastRealizedItemIndex,
             Rect lastRealizedLayoutBounds)
         {
@@ -121,7 +121,7 @@ namespace Avalonia.Layout
         }
 
         internal void OnElementMeasured(
-            ILayoutable element,
+            Layoutable element,
             int index,
             Size availableSize,
             Size measureSize,
@@ -188,10 +188,10 @@ namespace Avalonia.Layout
         Rect IFlowLayoutAlgorithmDelegates.Algorithm_GetExtent(
             Size availableSize,
             VirtualizingLayoutContext context,
-            ILayoutable? firstRealized,
+            Layoutable? firstRealized,
             int firstRealizedItemIndex,
             Rect firstRealizedLayoutBounds,
-            ILayoutable? lastRealized,
+            Layoutable? lastRealized,
             int lastRealizedItemIndex,
             Rect lastRealizedLayoutBounds)
         {
@@ -206,7 +206,7 @@ namespace Avalonia.Layout
                 lastRealizedLayoutBounds);
         }
 
-        void IFlowLayoutAlgorithmDelegates.Algorithm_OnElementMeasured(ILayoutable element, int index, Size availableSize, Size measureSize, Size desiredSize, Size provisionalArrangeSize, VirtualizingLayoutContext context)
+        void IFlowLayoutAlgorithmDelegates.Algorithm_OnElementMeasured(Layoutable element, int index, Size availableSize, Size measureSize, Size desiredSize, Size provisionalArrangeSize, VirtualizingLayoutContext context)
         {
             OnElementMeasured(
                 element,

+ 3 - 3
src/Avalonia.Base/Layout/UniformGridLayout.cs

@@ -338,10 +338,10 @@ namespace Avalonia.Layout
         Rect IFlowLayoutAlgorithmDelegates.Algorithm_GetExtent(
             Size availableSize,
             VirtualizingLayoutContext context,
-            ILayoutable? firstRealized,
+            Layoutable? firstRealized,
             int firstRealizedItemIndex,
             Rect firstRealizedLayoutBounds,
-            ILayoutable? lastRealized,
+            Layoutable? lastRealized,
             int lastRealizedItemIndex,
             Rect lastRealizedLayoutBounds)
         {
@@ -391,7 +391,7 @@ namespace Avalonia.Layout
             return extent;
         }
 
-        void IFlowLayoutAlgorithmDelegates.Algorithm_OnElementMeasured(ILayoutable element, int index, Size availableSize, Size measureSize, Size desiredSize, Size provisionalArrangeSize, VirtualizingLayoutContext context)
+        void IFlowLayoutAlgorithmDelegates.Algorithm_OnElementMeasured(Layoutable element, int index, Size availableSize, Size measureSize, Size desiredSize, Size provisionalArrangeSize, VirtualizingLayoutContext context)
         {
         }
 

+ 2 - 2
src/Avalonia.Base/Layout/UniformGridLayoutState.cs

@@ -18,7 +18,7 @@ namespace Avalonia.Layout
         // If it does not, then we need to do context.GetElement(0) at which point we have requested an element and are on point to clear it.
         // If we are responsible for clearing element 0 we keep m_cachedFirstElement valid. 
         // If we are not (because FlowLayoutAlgorithm is holding it for us) then we just null out this field and use the one from FlowLayoutAlgorithm.
-        private ILayoutable? _cachedFirstElement;
+        private Layoutable? _cachedFirstElement;
 
         internal FlowLayoutAlgorithm FlowAlgorithm { get; } = new FlowLayoutAlgorithm();
         internal double EffectiveItemWidth { get; private set; }
@@ -91,7 +91,7 @@ namespace Avalonia.Layout
         }
 
         private void SetSize(
-            ILayoutable element,
+            Layoutable element,
             double layoutItemWidth,
             double layoutItemHeight,
             Size availableSize,

+ 4 - 4
src/Avalonia.Base/Layout/VirtualLayoutContextAdapter.cs

@@ -19,18 +19,18 @@ namespace Avalonia.Layout
             set => _virtualizingContext.LayoutState = value;
         }
 
-        protected override IReadOnlyList<ILayoutable> ChildrenCore =>
+        protected override IReadOnlyList<Layoutable> ChildrenCore =>
             _children ?? (_children = new ChildrenCollection(_virtualizingContext));
 
-        private class ChildrenCollection : IReadOnlyList<ILayoutable>
+        private class ChildrenCollection : IReadOnlyList<Layoutable>
         {
             private readonly VirtualizingLayoutContext _context;
             public ChildrenCollection(VirtualizingLayoutContext context) => _context = context;
-            public ILayoutable this[int index] => _context.GetOrCreateElementAt(index);
+            public Layoutable this[int index] => _context.GetOrCreateElementAt(index);
             public int Count => _context.ItemCount;
             IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
-            public IEnumerator<ILayoutable> GetEnumerator()
+            public IEnumerator<Layoutable> GetEnumerator()
             {
                 for (var i = 0; i < Count; ++i)
                 {

+ 6 - 6
src/Avalonia.Base/Layout/VirtualizingLayoutContext.cs

@@ -116,7 +116,7 @@ namespace Avalonia.Layout
         /// This method calls <see cref="GetOrCreateElementAtCore(int, ElementRealizationOptions)"/>
         /// with options set to None. GetElementAtCore must be implemented in a derived class.
         /// </remarks>
-        public ILayoutable GetOrCreateElementAt(int index)
+        public Layoutable GetOrCreateElementAt(int index)
             => GetOrCreateElementAtCore(index, ElementRealizationOptions.None);
 
         /// <summary>
@@ -140,7 +140,7 @@ namespace Avalonia.Layout
         /// advanced layouts that choose to explicitly manage the realization and recycling of
         /// elements as a performance optimization.
         /// </remarks>
-        public ILayoutable GetOrCreateElementAt(int index, ElementRealizationOptions options)
+        public Layoutable GetOrCreateElementAt(int index, ElementRealizationOptions options)
             => GetOrCreateElementAtCore(index, options);
 
         /// <summary>
@@ -148,10 +148,10 @@ namespace Avalonia.Layout
         /// </summary>
         /// <param name="element">The element to clear.</param>
         /// <remarks>
-        /// This method calls <see cref="RecycleElementCore(ILayoutable)"/>, which must be implemented
+        /// This method calls <see cref="RecycleElementCore(Layoutable)"/>, which must be implemented
         /// in a derived class.
         /// </remarks>
-        public void RecycleElement(ILayoutable element) => RecycleElementCore(element);
+        public void RecycleElement(Layoutable element) => RecycleElementCore(element);
 
         /// <summary>
         /// When implemented in a derived class, retrieves the number of items in the data.
@@ -180,14 +180,14 @@ namespace Avalonia.Layout
         /// A value of <see cref="ElementRealizationOptions"/> that specifies whether to suppress
         /// automatic recycling of the retrieved element or force creation of a new element.
         /// </param>
-        protected abstract ILayoutable GetOrCreateElementAtCore(int index, ElementRealizationOptions options);
+        protected abstract Layoutable GetOrCreateElementAtCore(int index, ElementRealizationOptions options);
 
         /// <summary>
         /// When implemented in a derived class, clears the specified UIElement and allows it to be
         /// either re-used or released.
         /// </summary>
         /// <param name="element">The element to clear.</param>
-        protected abstract void RecycleElementCore(ILayoutable element);
+        protected abstract void RecycleElementCore(Layoutable element);
 
         internal NonVirtualizingLayoutContext GetNonVirtualizingContextAdapter() =>
             _contextAdapter ?? (_contextAdapter = new VirtualLayoutContextAdapter(this));

+ 1 - 1
src/Avalonia.Base/Layout/WrapLayout/WrapItem.cs

@@ -20,6 +20,6 @@ namespace Avalonia.Layout
 
         public UvMeasure? Position { get; internal set; }
 
-        public ILayoutable? Element { get; internal set; }
+        public Layoutable? Element { get; internal set; }
     }
 }

+ 2 - 2
src/Avalonia.Base/Media/IVisualBrush.cs

@@ -4,7 +4,7 @@ using Avalonia.VisualTree;
 namespace Avalonia.Media
 {
     /// <summary>
-    /// Paints an area with an <see cref="IVisual"/>.
+    /// Paints an area with an <see cref="Visual"/>.
     /// </summary>
     [NotClientImplementable]
     public interface IVisualBrush : ITileBrush
@@ -12,6 +12,6 @@ namespace Avalonia.Media
         /// <summary>
         /// Gets the visual to draw.
         /// </summary>
-        IVisual Visual { get; }
+        Visual Visual { get; }
     }
 }

+ 1 - 1
src/Avalonia.Base/Media/Imaging/RenderTargetBitmap.cs

@@ -44,7 +44,7 @@ namespace Avalonia.Media.Imaging
         /// Renders a visual to the <see cref="RenderTargetBitmap"/>.
         /// </summary>
         /// <param name="visual">The visual to render.</param>
-        public void Render(IVisual visual) => ImmediateRenderer.Render(visual, this);
+        public void Render(Visual visual) => ImmediateRenderer.Render(visual, this);
 
         /// <summary>
         /// Creates a platform-specific implementation for a <see cref="RenderTargetBitmap"/>.

+ 2 - 2
src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs

@@ -25,7 +25,7 @@ namespace Avalonia.Media.Immutable
         /// <param name="tileMode">The tile mode.</param>
         /// <param name="bitmapInterpolationMode">Controls the quality of interpolation.</param>
         public ImmutableVisualBrush(
-            IVisual visual,
+            Visual visual,
             AlignmentX alignmentX = AlignmentX.Center,
             AlignmentY alignmentY = AlignmentY.Center,
             RelativeRect? destinationRect = null,
@@ -62,6 +62,6 @@ namespace Avalonia.Media.Immutable
         }
 
         /// <inheritdoc/>
-        public IVisual Visual { get; }
+        public Visual Visual { get; }
     }
 }

+ 5 - 5
src/Avalonia.Base/Media/VisualBrush.cs

@@ -4,15 +4,15 @@ using Avalonia.VisualTree;
 namespace Avalonia.Media
 {
     /// <summary>
-    /// Paints an area with an <see cref="IVisual"/>.
+    /// Paints an area with an <see cref="Visual"/>.
     /// </summary>
     public class VisualBrush : TileBrush, IVisualBrush
     {
         /// <summary>
         /// Defines the <see cref="Visual"/> property.
         /// </summary>
-        public static readonly StyledProperty<IVisual> VisualProperty =
-            AvaloniaProperty.Register<VisualBrush, IVisual>(nameof(Visual));
+        public static readonly StyledProperty<Visual> VisualProperty =
+            AvaloniaProperty.Register<VisualBrush, Visual>(nameof(Visual));
 
         static VisualBrush()
         {
@@ -30,7 +30,7 @@ namespace Avalonia.Media
         /// Initializes a new instance of the <see cref="VisualBrush"/> class.
         /// </summary>
         /// <param name="visual">The visual to draw.</param>
-        public VisualBrush(IVisual visual)
+        public VisualBrush(Visual visual)
         {
             Visual = visual;
         }
@@ -38,7 +38,7 @@ namespace Avalonia.Media
         /// <summary>
         /// Gets or sets the visual to draw.
         /// </summary>
-        public IVisual Visual
+        public Visual Visual
         {
             get { return GetValue(VisualProperty); }
             set { SetValue(VisualProperty, value); }

+ 1 - 1
src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs

@@ -262,7 +262,7 @@ namespace Avalonia.PropertyStore
 
         private class UncommonFields
         {
-            public Func<IAvaloniaObject, T, T>? _coerce;
+            public Func<AvaloniaObject, T, T>? _coerce;
             public T? _uncoercedValue;
             public T? _uncoercedBaseValue;
         }

+ 0 - 12
src/Avalonia.Base/PropertyStore/UntypedValueUtils.cs

@@ -23,18 +23,6 @@ namespace Avalonia.PropertyStore
             return v;
         }
 
-        public static bool TryConvertAndValidate(
-            AvaloniaProperty property,
-            object? value,
-            out object? result)
-        {
-            if (TypeUtilities.TryConvertImplicit(property.PropertyType, value, out result))
-                return ((IStyledPropertyAccessor)property).ValidateValue(result);
-
-            result = default;
-            return false;
-        }
-
         public static bool TryConvertAndValidate<T>(
             StyledPropertyBase<T> property,
             object? value, 

+ 3 - 3
src/Avalonia.Base/Reactive/AvaloniaPropertyBindingObservable.cs

@@ -6,15 +6,15 @@ namespace Avalonia.Reactive
 {
     internal class AvaloniaPropertyBindingObservable<T> : LightweightObservableBase<BindingValue<T>>, IDescription
     {
-        private readonly WeakReference<IAvaloniaObject> _target;
+        private readonly WeakReference<AvaloniaObject> _target;
         private readonly AvaloniaProperty _property;
         private BindingValue<T> _value = BindingValue<T>.Unset;
 
         public AvaloniaPropertyBindingObservable(
-            IAvaloniaObject target,
+            AvaloniaObject target,
             AvaloniaProperty property)
         {
-            _target = new WeakReference<IAvaloniaObject>(target);
+            _target = new WeakReference<AvaloniaObject>(target);
             _property = property;
         }
 

+ 3 - 3
src/Avalonia.Base/Reactive/AvaloniaPropertyChangedObservable.cs

@@ -6,14 +6,14 @@ namespace Avalonia.Reactive
         LightweightObservableBase<AvaloniaPropertyChangedEventArgs>,
         IDescription
     {
-        private readonly WeakReference<IAvaloniaObject> _target;
+        private readonly WeakReference<AvaloniaObject> _target;
         private readonly AvaloniaProperty _property;
 
         public AvaloniaPropertyChangedObservable(
-            IAvaloniaObject target,
+            AvaloniaObject target,
             AvaloniaProperty property)
         {
-            _target = new WeakReference<IAvaloniaObject>(target);
+            _target = new WeakReference<AvaloniaObject>(target);
             _property = property;
         }
 

+ 14 - 22
src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs

@@ -6,15 +6,15 @@ namespace Avalonia.Reactive
 {
     internal class AvaloniaPropertyObservable<T> : LightweightObservableBase<T>, IDescription
     {
-        private readonly WeakReference<IAvaloniaObject> _target;
+        private readonly WeakReference<AvaloniaObject> _target;
         private readonly AvaloniaProperty _property;
         private Optional<T> _value;
 
         public AvaloniaPropertyObservable(
-            IAvaloniaObject target,
+            AvaloniaObject target,
             AvaloniaProperty property)
         {
-            _target = new WeakReference<IAvaloniaObject>(target);
+            _target = new WeakReference<AvaloniaObject>(target);
             _property = property;
         }
 
@@ -49,31 +49,23 @@ namespace Avalonia.Reactive
         {
             if (e.Property == _property)
             {
-                if (e.Sender is AvaloniaObject ao)
-                {
-                    T newValue;
-
-                    if (e is AvaloniaPropertyChangedEventArgs<T> typed)
-                    {
-                        newValue = AvaloniaObjectExtensions.GetValue(ao, typed.Property);
-                    }
-                    else
-                    {
-                        newValue = (T)e.Sender.GetValue(e.Property)!;
-                    }
+                T newValue;
 
-                    if (!_value.HasValue ||
-                        !EqualityComparer<T>.Default.Equals(newValue, _value.Value))
-                    {
-                        _value = newValue;
-                        PublishNext(_value.Value!);
-                    }
+                if (e is AvaloniaPropertyChangedEventArgs<T> typed)
+                {
+                    newValue = AvaloniaObjectExtensions.GetValue(e.Sender, typed.Property);
                 }
                 else
                 {
-                    throw new NotSupportedException("Custom implementations of IAvaloniaObject not supported.");
+                    newValue = (T)e.Sender.GetValue(e.Property)!;
                 }
 
+                if (!_value.HasValue ||
+                    !EqualityComparer<T>.Default.Equals(newValue, _value.Value))
+                {
+                    _value = newValue;
+                    PublishNext(_value.Value!);
+                }
             }
         }
     }

+ 7 - 7
src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

@@ -45,7 +45,7 @@ public class CompositingRenderer : IRendererWithCompositor
         _compositor = compositor;
         _recordingContext = new DrawingContext(_recorder);
         CompositionTarget = compositor.CreateCompositionTarget(root.CreateRenderTarget);
-        CompositionTarget.Root = ((Visual)root!.VisualRoot!).AttachToCompositor(compositor);
+        CompositionTarget.Root = ((Visual)root).AttachToCompositor(compositor);
         _update = Update;
     }
 
@@ -75,7 +75,7 @@ public class CompositingRenderer : IRendererWithCompositor
     }
     
     /// <inheritdoc/>
-    public void AddDirty(IVisual visual)
+    public void AddDirty(Visual visual)
     {
         if (_updating)
             throw new InvalidOperationException("Visual was invalidated during the render pass");
@@ -84,7 +84,7 @@ public class CompositingRenderer : IRendererWithCompositor
     }
 
     /// <inheritdoc/>
-    public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool>? filter)
+    public IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool>? filter)
     {
         Func<CompositionVisual, bool>? f = null;
         if (filter != null)
@@ -109,14 +109,14 @@ public class CompositingRenderer : IRendererWithCompositor
     }
 
     /// <inheritdoc/>
-    public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool>? filter)
+    public Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool>? filter)
     {
         // TODO: Optimize
         return HitTest(p, root, filter).FirstOrDefault();
     }
 
     /// <inheritdoc/>
-    public void RecalculateChildren(IVisual visual)
+    public void RecalculateChildren(Visual visual)
     {
         if (_updating)
             throw new InvalidOperationException("Visual was invalidated during the render pass");
@@ -130,9 +130,9 @@ public class CompositingRenderer : IRendererWithCompositor
         if(v.CompositionVisual == null)
             return;
         var compositionChildren = v.CompositionVisual.Children;
-        var visualChildren = (AvaloniaList<IVisual>)v.GetVisualChildren();
+        var visualChildren = (AvaloniaList<Visual>)v.GetVisualChildren();
         
-        PooledList<(IVisual visual, int index)>? sortedChildren = null;
+        PooledList<(Visual visual, int index)>? sortedChildren = null;
         if (v.HasNonUniformZIndexChildren && visualChildren.Count > 1)
         {
             sortedChildren = new (visualChildren.Count);

+ 11 - 11
src/Avalonia.Base/Rendering/DeferredRenderer.cs

@@ -22,14 +22,14 @@ namespace Avalonia.Rendering
     {
         private readonly IDispatcher? _dispatcher;
         private readonly IRenderLoop? _renderLoop;
-        private readonly IVisual _root;
+        private readonly Visual _root;
         private readonly ISceneBuilder _sceneBuilder;
 
         private bool _running;
         private bool _disposed;
         private volatile IRef<Scene>? _scene;
         private DirtyVisuals? _dirty;
-        private HashSet<IVisual>? _recalculateChildren;
+        private HashSet<Visual>? _recalculateChildren;
         private IRef<IRenderTargetBitmapImpl>? _overlay;
         private int _lastSceneId = -1;
         private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects();
@@ -56,7 +56,7 @@ namespace Avalonia.Rendering
             IDeferredRendererLock? rendererLock = null) : base(true)
         {
             _dispatcher = dispatcher ?? Dispatcher.UIThread;
-            _root = root ?? throw new ArgumentNullException(nameof(root));
+            _root = root as Visual ?? throw new ArgumentNullException(nameof(root));
             _sceneBuilder = sceneBuilder ?? new SceneBuilder();
             Layers = new RenderLayers();
             _renderLoop = renderLoop;
@@ -74,7 +74,7 @@ namespace Avalonia.Rendering
         /// This constructor is intended to be used for unit testing.
         /// </remarks>
         public DeferredRenderer(
-            IVisual root,
+            Visual root,
             IRenderTarget renderTarget,
             ISceneBuilder? sceneBuilder = null) : base(true)
         {
@@ -116,7 +116,7 @@ namespace Avalonia.Rendering
         internal IRenderTarget? RenderTarget { get; private set; }
 
         /// <inheritdoc/>
-        public void AddDirty(IVisual visual)
+        public void AddDirty(Visual visual)
         {
             _dirty?.Add(visual);
         }
@@ -142,7 +142,7 @@ namespace Avalonia.Rendering
             DisposeRenderTarget();
         }
 
-        public void RecalculateChildren(IVisual visual) => _recalculateChildren?.Add(visual);
+        public void RecalculateChildren(Visual visual) => _recalculateChildren?.Add(visual);
 
         void DisposeRenderTarget()
         {
@@ -163,17 +163,17 @@ namespace Avalonia.Rendering
         }
 
         /// <inheritdoc/>
-        public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool>? filter)
+        public IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool>? filter)
         {
             EnsureCanHitTest();
 
             //It's safe to access _scene here without a lock since
             //it's only changed from UI thread which we are currently on
-            return _scene?.Item.HitTest(p, root, filter) ?? Enumerable.Empty<IVisual>();
+            return _scene?.Item.HitTest(p, root, filter) ?? Enumerable.Empty<Visual>();
         }
 
         /// <inheritdoc/>
-        public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool>? filter)
+        public Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool>? filter)
         {
             EnsureCanHitTest();
 
@@ -414,7 +414,7 @@ namespace Avalonia.Rendering
         }
 
 
-        private void Render(IDrawingContextImpl context, VisualNode node, IVisual? layer, Rect clipBounds)
+        private void Render(IDrawingContextImpl context, VisualNode node, Visual? layer, Rect clipBounds)
         {
             if (layer == null || node.LayerRoot == layer)
             {
@@ -643,7 +643,7 @@ namespace Avalonia.Rendering
                 if (_dirty == null)
                 {
                     _dirty = new DirtyVisuals();
-                    _recalculateChildren = new HashSet<IVisual>();
+                    _recalculateChildren = new HashSet<Visual>();
                     _sceneBuilder.UpdateAll(scene);
                 }
                 else

+ 7 - 7
src/Avalonia.Base/Rendering/DirtyVisuals.cs

@@ -13,10 +13,10 @@ namespace Avalonia.Rendering
     /// visual. TODO: We probably want to put an upper limit on the number of visuals that can be
     /// stored and if we reach that limit, assume all visuals are dirty.
     /// </remarks>
-    internal class DirtyVisuals : IEnumerable<IVisual>
+    internal class DirtyVisuals : IEnumerable<Visual>
     {
-        private SortedDictionary<int, List<IVisual>> _inner = new SortedDictionary<int, List<IVisual>>();
-        private Dictionary<IVisual, int> _index = new Dictionary<IVisual, int>();
+        private SortedDictionary<int, List<Visual>> _inner = new SortedDictionary<int, List<Visual>>();
+        private Dictionary<Visual, int> _index = new Dictionary<Visual, int>();
         private int _enumerating;
 
         /// <summary>
@@ -28,14 +28,14 @@ namespace Avalonia.Rendering
         /// Adds a visual to the dirty list.
         /// </summary>
         /// <param name="visual">The dirty visual.</param>
-        public void Add(IVisual visual)
+        public void Add(Visual visual)
         {
             if (_enumerating > 0)
             {
                 throw new InvalidOperationException("Visual was invalidated during a render pass");
             }
 
-            var distance = visual.CalculateDistanceFromAncestor(visual.VisualRoot);
+            var distance = visual.CalculateDistanceFromAncestor((Visual?)visual.GetVisualRoot());
 
             if (_index.TryGetValue(visual, out var existingDistance))
             {
@@ -50,7 +50,7 @@ namespace Avalonia.Rendering
 
             if (!_inner.TryGetValue(distance, out var list))
             {
-                list = new List<IVisual>();
+                list = new List<Visual>();
                 _inner.Add(distance, list);
             }
 
@@ -76,7 +76,7 @@ namespace Avalonia.Rendering
         /// Gets the dirty visuals, in ascending order of distance to their root.
         /// </summary>
         /// <returns>A collection of visuals.</returns>
-        public IEnumerator<IVisual> GetEnumerator()
+        public IEnumerator<Visual> GetEnumerator()
         {
             _enumerating++;
             try

+ 2 - 2
src/Avalonia.Base/Rendering/ICustomSimpleHitTest.cs

@@ -24,10 +24,10 @@ namespace Avalonia.Rendering
 
     public static class CustomSimpleHitTestExtensions
     {
-        public static bool HitTestCustom(this IVisual visual, Point point)
+        public static bool HitTestCustom(this Visual visual, Point point)
             => (visual as ICustomSimpleHitTest)?.HitTest(point) ?? visual.TransformedBounds?.Contains(point) == true;
 
-        public static bool HitTestCustom(this IEnumerable<IVisual> children, Point point)
+        public static bool HitTestCustom(this IEnumerable<Visual> children, Point point)
             => children.Any(ctrl => ctrl.HitTestCustom(point));
     }
 }

+ 1 - 1
src/Avalonia.Base/Rendering/IRenderRoot.cs

@@ -8,7 +8,7 @@ namespace Avalonia.Rendering
     /// Represents the root of a renderable tree.
     /// </summary>
     [NotClientImplementable]
-    public interface IRenderRoot : IVisual
+    public interface IRenderRoot
     {
         /// <summary>
         /// Gets the client size of the window.

+ 4 - 4
src/Avalonia.Base/Rendering/IRenderer.cs

@@ -34,7 +34,7 @@ namespace Avalonia.Rendering
         /// Mark a visual as dirty and needing re-rendering.
         /// </summary>
         /// <param name="visual">The visual.</param>
-        void AddDirty(IVisual visual);
+        void AddDirty(Visual visual);
 
         /// <summary>
         /// Hit tests a location to find the visuals at the specified point.
@@ -46,7 +46,7 @@ namespace Avalonia.Rendering
         /// children will be excluded from the results.
         /// </param>
         /// <returns>The visuals at the specified point, topmost first.</returns>
-        IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter);
+        IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool> filter);
 
         /// <summary>
         /// Hit tests a location to find first visual at the specified point.
@@ -58,13 +58,13 @@ namespace Avalonia.Rendering
         /// children will be excluded from the results.
         /// </param>
         /// <returns>The visual at the specified point, topmost first.</returns>
-        IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool> filter);
+        Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool> filter);
 
         /// <summary>
         /// Informs the renderer that the z-ordering of a visual's children has changed.
         /// </summary>
         /// <param name="visual">The visual.</param>
-        void RecalculateChildren(IVisual visual);
+        void RecalculateChildren(Visual visual);
 
         /// <summary>
         /// Called when a resize notification is received by the control being rendered.

+ 19 - 19
src/Avalonia.Base/Rendering/ImmediateRenderer.cs

@@ -18,7 +18,7 @@ namespace Avalonia.Rendering
     /// </remarks>
     public class ImmediateRenderer : RendererBase, IRenderer, IVisualBrushRenderer
     {
-        private readonly IVisual _root;
+        private readonly Visual _root;
         private readonly IRenderRoot? _renderRoot;
         private bool _updateTransformedBounds = true;
         private IRenderTarget? _renderTarget;
@@ -27,13 +27,13 @@ namespace Avalonia.Rendering
         /// Initializes a new instance of the <see cref="ImmediateRenderer"/> class.
         /// </summary>
         /// <param name="root">The control to render.</param>
-        public ImmediateRenderer(IVisual root)
+        public ImmediateRenderer(Visual root)
         {
             _root = root ?? throw new ArgumentNullException(nameof(root));
             _renderRoot = root as IRenderRoot;
         }
 
-        private ImmediateRenderer(IVisual root, bool updateTransformedBounds)
+        private ImmediateRenderer(Visual root, bool updateTransformedBounds)
         {
             _root = root ?? throw new ArgumentNullException(nameof(root));
             _renderRoot = root as IRenderRoot;
@@ -102,7 +102,7 @@ namespace Avalonia.Rendering
         /// </summary>
         /// <param name="visual">The visual.</param>
         /// <param name="target">The render target.</param>
-        public static void Render(IVisual visual, IRenderTarget target)
+        public static void Render(Visual visual, IRenderTarget target)
         {
             using (var renderer = new ImmediateRenderer(visual, updateTransformedBounds: false))
             using (var context = new DrawingContext(target.CreateDrawingContext(renderer)))
@@ -116,7 +116,7 @@ namespace Avalonia.Rendering
         /// </summary>
         /// <param name="visual">The visual.</param>
         /// <param name="context">The drawing context.</param>
-        public static void Render(IVisual visual, DrawingContext context)
+        public static void Render(Visual visual, DrawingContext context)
         {
             using (var renderer = new ImmediateRenderer(visual, updateTransformedBounds: false))
             {
@@ -125,7 +125,7 @@ namespace Avalonia.Rendering
         }
 
         /// <inheritdoc/>
-        public void AddDirty(IVisual visual)
+        public void AddDirty(Visual visual)
         {
             if (visual.Bounds != Rect.Empty)
             {
@@ -162,18 +162,18 @@ namespace Avalonia.Rendering
         }
 
         /// <inheritdoc/>
-        public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter)
+        public IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool> filter)
         {
             return HitTest(root, p, filter);
         }
 
-        public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool> filter)
+        public Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool> filter)
         {
             return HitTest(root, p, filter).FirstOrDefault();
         }
 
         /// <inheritdoc/>
-        public void RecalculateChildren(IVisual visual) => AddDirty(visual);
+        public void RecalculateChildren(Visual visual) => AddDirty(visual);
 
         /// <inheritdoc/>
         public void Start()
@@ -199,21 +199,21 @@ namespace Avalonia.Rendering
             Render(new DrawingContext(context), visual, visual.Bounds);
         }
 
-        internal static void Render(IVisual visual, DrawingContext context, bool updateTransformedBounds)
+        internal static void Render(Visual visual, DrawingContext context, bool updateTransformedBounds)
         {
             using var renderer = new ImmediateRenderer(visual, updateTransformedBounds);
             renderer.Render(context, visual, visual.Bounds);
         }
 
-        private static void ClearTransformedBounds(IVisual visual)
+        private static void ClearTransformedBounds(Visual visual)
         {
             foreach (var e in visual.GetSelfAndVisualDescendants())
             {
-                visual.TransformedBounds = null;
+                visual.SetTransformedBounds(null);
             }
         }
 
-        private static Rect GetTransformedBounds(IVisual visual)
+        private static Rect GetTransformedBounds(Visual visual)
         {
             if (visual.RenderTransform == null)
             {
@@ -228,10 +228,10 @@ namespace Avalonia.Rendering
             }
         }
 
-        private static IEnumerable<IVisual> HitTest(
-           IVisual visual,
+        private static IEnumerable<Visual> HitTest(
+           Visual visual,
            Point p,
-           Func<IVisual, bool>? filter)
+           Func<Visual, bool>? filter)
         {
             _ = visual ?? throw new ArgumentNullException(nameof(visual));
 
@@ -266,7 +266,7 @@ namespace Avalonia.Rendering
             }
         }
 
-        private void Render(DrawingContext context, IVisual visual, Rect clipRect)
+        private void Render(DrawingContext context, Visual visual, Rect clipRect)
         {
             var opacity = visual.Opacity;
             var clipToBounds = visual.ClipToBounds;
@@ -329,11 +329,11 @@ namespace Avalonia.Rendering
 #pragma warning restore 0618
 
                     if (_updateTransformedBounds)
-                        visual.TransformedBounds = transformed;
+                        visual.SetTransformedBounds(transformed);
 
                     var childrenEnumerable = visual.HasNonUniformZIndexChildren
                         ? visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance)
-                        : (IEnumerable<IVisual>)visual.VisualChildren;
+                        : (IEnumerable<Visual>)visual.VisualChildren;
                     
                     foreach (var child in childrenEnumerable)
                     {

+ 2 - 2
src/Avalonia.Base/Rendering/RenderLayer.cs

@@ -11,7 +11,7 @@ namespace Avalonia.Rendering
             IDrawingContextImpl drawingContext,
             Size size,
             double scaling,
-            IVisual layerRoot)
+            Visual layerRoot)
         {
             Bitmap = RefCountable.Create(drawingContext.CreateLayer(size));
             Size = size;
@@ -24,7 +24,7 @@ namespace Avalonia.Rendering
         public bool IsEmpty { get; set; }
         public double Scaling { get; private set; }
         public Size Size { get; private set; }
-        public IVisual LayerRoot { get; }
+        public Visual LayerRoot { get; }
 
         public void RecreateBitmap(IDrawingContextImpl drawingContext, Size size, double scaling)
         {

+ 3 - 4
src/Avalonia.Base/Rendering/RenderLayers.cs

@@ -3,17 +3,16 @@ using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 using Avalonia.Platform;
 using Avalonia.Rendering.SceneGraph;
-using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering
 {
     public class RenderLayers : IEnumerable<RenderLayer>
     {
         private readonly List<RenderLayer> _inner = new List<RenderLayer>();
-        private readonly Dictionary<IVisual, RenderLayer> _index = new Dictionary<IVisual, RenderLayer>();
+        private readonly Dictionary<Visual, RenderLayer> _index = new Dictionary<Visual, RenderLayer>();
         
         public int Count => _inner.Count;
-        public RenderLayer this[IVisual layerRoot] => _index[layerRoot];
+        public RenderLayer this[Visual layerRoot] => _index[layerRoot];
 
         public void Update(Scene scene, IDrawingContextImpl context)
         {
@@ -59,7 +58,7 @@ namespace Avalonia.Rendering
             _inner.Clear();
         }
 
-        public bool TryGetValue(IVisual layerRoot, [NotNullWhen(true)] out RenderLayer? value)
+        public bool TryGetValue(Visual layerRoot, [NotNullWhen(true)] out RenderLayer? value)
         {
             return _index.TryGetValue(layerRoot, out value);
         }

+ 2 - 2
src/Avalonia.Base/Rendering/SceneGraph/ISceneBuilder.cs

@@ -19,6 +19,6 @@ namespace Avalonia.Rendering.SceneGraph
         /// <param name="scene">The scene.</param>
         /// <param name="visual">The visual to update.</param>
         /// <returns>True if changes were made, otherwise false.</returns>
-        bool Update(Scene scene, IVisual visual);
+        bool Update(Scene scene, Visual visual);
     }
-}
+}

+ 2 - 3
src/Avalonia.Base/Rendering/SceneGraph/IVisualNode.cs

@@ -2,19 +2,18 @@
 using System.Collections.Generic;
 using Avalonia.Platform;
 using Avalonia.Utilities;
-using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
     /// <summary>
-    /// Represents a node in the low-level scene graph representing an <see cref="IVisual"/>.
+    /// Represents a node in the low-level scene graph representing a <see cref="Visual"/>.
     /// </summary>
     public interface IVisualNode : IDisposable
     {
         /// <summary>
         /// Gets the visual to which the node relates.
         /// </summary>
-        IVisual Visual { get; }
+        Visual Visual { get; }
 
         /// <summary>
         /// Gets the parent scene graph node.

+ 20 - 20
src/Avalonia.Base/Rendering/SceneGraph/Scene.cs

@@ -13,24 +13,24 @@ namespace Avalonia.Rendering.SceneGraph
     /// </summary>
     public class Scene : IDisposable
     {
-        private readonly Dictionary<IVisual, IVisualNode> _index;
+        private readonly Dictionary<Visual, IVisualNode> _index;
         private readonly TaskCompletionSource<bool> _rendered = new TaskCompletionSource<bool>();
 
         /// <summary>
         /// Initializes a new instance of the <see cref="Scene"/> class.
         /// </summary>
         /// <param name="rootVisual">The root visual to draw.</param>
-        public Scene(IVisual rootVisual)
+        public Scene(Visual rootVisual)
             : this(
                 new VisualNode(rootVisual, null),
-                new Dictionary<IVisual, IVisualNode>(),
+                new Dictionary<Visual, IVisualNode>(),
                 new SceneLayers(rootVisual),
                 0)
         {
             _index.Add(rootVisual, Root);
         }
 
-        private Scene(VisualNode root, Dictionary<IVisual, IVisualNode> index, SceneLayers layers, int generation)
+        private Scene(VisualNode root, Dictionary<Visual, IVisualNode> index, SceneLayers layers, int generation)
         {
             _ = root ?? throw new ArgumentNullException(nameof(root));
 
@@ -87,7 +87,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// <returns>The cloned scene.</returns>
         public Scene CloneScene()
         {
-            var index = new Dictionary<IVisual, IVisualNode>(_index.Count);
+            var index = new Dictionary<Visual, IVisualNode>(_index.Count);
             var root = Clone((VisualNode)Root, null, index);
 
             var result = new Scene(root, index, Layers.Clone(), Generation + 1)
@@ -115,7 +115,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// <returns>
         /// The node representing the visual or null if it could not be found.
         /// </returns>
-        public IVisualNode? FindNode(IVisual visual)
+        public IVisualNode? FindNode(Visual visual)
         {
             _index.TryGetValue(visual, out var node);
             return node;
@@ -128,10 +128,10 @@ namespace Avalonia.Rendering.SceneGraph
         /// <param name="root">The root of the subtree to search.</param>
         /// <param name="filter">A filter. May be null.</param>
         /// <returns>The visuals at the specified point.</returns>
-        public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool>? filter)
+        public IEnumerable<Visual> HitTest(Point p, Visual root, Func<Visual, bool>? filter)
         {
             var node = FindNode(root);
-            return (node != null) ? new HitTestEnumerable(node, filter, p, Root) : Enumerable.Empty<IVisual>();
+            return (node != null) ? new HitTestEnumerable(node, filter, p, Root) : Enumerable.Empty<Visual>();
         }
 
         /// <summary>
@@ -141,7 +141,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// <param name="root">The root of the subtree to search.</param>
         /// <param name="filter">A filter. May be null.</param>
         /// <returns>The visual at the specified point.</returns>
-        public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool>? filter)
+        public Visual? HitTestFirst(Point p, Visual root, Func<Visual, bool>? filter)
         {
             var node = FindNode(root);
             return (node != null) ? HitTestFirst(node, p, filter) : null;
@@ -160,7 +160,7 @@ namespace Avalonia.Rendering.SceneGraph
             node.Dispose();
         }
 
-        private VisualNode Clone(VisualNode source, IVisualNode? parent, Dictionary<IVisual, IVisualNode> index)
+        private VisualNode Clone(VisualNode source, IVisualNode? parent, Dictionary<Visual, IVisualNode> index)
         {
             var result = source.Clone(parent);
 
@@ -184,7 +184,7 @@ namespace Avalonia.Rendering.SceneGraph
             return result;
         }
 
-        private IVisual HitTestFirst(IVisualNode root, Point p, Func<IVisual, bool>? filter)
+        private Visual HitTestFirst(IVisualNode root, Point p, Func<Visual, bool>? filter)
         {
             using var enumerator = new HitTestEnumerator(root, filter, p, Root);
 
@@ -193,14 +193,14 @@ namespace Avalonia.Rendering.SceneGraph
             return enumerator.Current;
         }
 
-        private class HitTestEnumerable : IEnumerable<IVisual>
+        private class HitTestEnumerable : IEnumerable<Visual>
         {
             private readonly IVisualNode _root;
-            private readonly Func<IVisual, bool>? _filter;
+            private readonly Func<Visual, bool>? _filter;
             private readonly IVisualNode _sceneRoot;
             private readonly Point _point;
             
-            public HitTestEnumerable(IVisualNode root, Func<IVisual, bool>? filter, Point point, IVisualNode sceneRoot)
+            public HitTestEnumerable(IVisualNode root, Func<Visual, bool>? filter, Point point, IVisualNode sceneRoot)
             {
                 _root = root;
                 _filter = filter;
@@ -208,7 +208,7 @@ namespace Avalonia.Rendering.SceneGraph
                 _sceneRoot = sceneRoot;
             }
 
-            public IEnumerator<IVisual> GetEnumerator()
+            public IEnumerator<Visual> GetEnumerator()
             {
                 return new HitTestEnumerator(_root, _filter, _point, _sceneRoot);
             }
@@ -219,15 +219,15 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
-        private struct HitTestEnumerator : IEnumerator<IVisual>
+        private struct HitTestEnumerator : IEnumerator<Visual>
         {
             private readonly PooledStack<Entry> _nodeStack;
-            private readonly Func<IVisual, bool>? _filter;
+            private readonly Func<Visual, bool>? _filter;
             private readonly IVisualNode _sceneRoot;
-            private IVisual? _current;
+            private Visual? _current;
             private readonly Point _point;
 
-            public HitTestEnumerator(IVisualNode root, Func<IVisual, bool>? filter, Point point, IVisualNode sceneRoot)
+            public HitTestEnumerator(IVisualNode root, Func<Visual, bool>? filter, Point point, IVisualNode sceneRoot)
             {
                 _nodeStack = new PooledStack<Entry>();
                 _nodeStack.Push(new Entry(root, false, null, true));
@@ -282,7 +282,7 @@ namespace Avalonia.Rendering.SceneGraph
                 throw new NotSupportedException();
             }
 
-            public IVisual Current => _current!;
+            public Visual Current => _current!;
 
             object IEnumerator.Current => Current;
 

+ 9 - 9
src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs

@@ -30,7 +30,7 @@ namespace Avalonia.Rendering.SceneGraph
         }
 
         /// <inheritdoc/>
-        public bool Update(Scene scene, IVisual visual)
+        public bool Update(Scene scene, Visual visual)
         {
             _ = scene ?? throw new ArgumentNullException(nameof(scene));
             _ = visual ?? throw new ArgumentNullException(nameof(visual));
@@ -120,7 +120,7 @@ namespace Avalonia.Rendering.SceneGraph
             return false;
         }
 
-        private static VisualNode? FindExistingAncestor(Scene scene, IVisual visual)
+        private static VisualNode? FindExistingAncestor(Scene scene, Visual visual)
         {
             var node = scene.FindNode(visual);
 
@@ -151,7 +151,7 @@ namespace Avalonia.Rendering.SceneGraph
             return (VisualNode)node;
         }
 
-        private static object GetOrCreateChildNode(Scene scene, IVisual child, VisualNode parent)
+        private static object GetOrCreateChildNode(Scene scene, Visual child, VisualNode parent)
         {
             var result = (VisualNode?)scene.FindNode(child);
 
@@ -259,11 +259,11 @@ namespace Avalonia.Rendering.SceneGraph
                     catch { }
 
                     var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform);
-                    visual.TransformedBounds = transformed;
+                    visual.SetTransformedBounds(transformed);
 
                     if (forceRecurse)
                     {
-                        var visualChildren = (IList<IVisual>) visual.VisualChildren;
+                        var visualChildren = (IList<Visual>) visual.VisualChildren;
 
                         node.TryPreallocateChildren(visualChildren.Count);
 
@@ -278,7 +278,7 @@ namespace Avalonia.Rendering.SceneGraph
 
                             if (visual.HasNonUniformZIndexChildren)
                             {
-                                var sortedChildren = new (IVisual visual, int index)[count];
+                                var sortedChildren = new (Visual visual, int index)[count];
 
                                 for (var i = 0; i < count; i++)
                                 {
@@ -352,7 +352,7 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
-        private static VisualNode CreateNode(Scene scene, IVisual visual, VisualNode parent)
+        private static VisualNode CreateNode(Scene scene, Visual visual, VisualNode parent)
         {
             var node = new VisualNode(visual, parent);
             node.LayerRoot = parent.LayerRoot;
@@ -379,7 +379,7 @@ namespace Avalonia.Rendering.SceneGraph
 
             scene.Layers[node.LayerRoot!].Dirty.Add(node.Bounds);
 
-            node.Visual.TransformedBounds = null;
+            node.Visual.SetTransformedBounds(null);
 
             if (node.LayerRoot == node.Visual && node.Visual != scene.Root.Visual)
             {
@@ -455,7 +455,7 @@ namespace Avalonia.Rendering.SceneGraph
         }
 
         // HACK: Disabled layers because they're broken in current renderer. See #2244.
-        private static bool ShouldStartLayer(IVisual visual) => false;
+        private static bool ShouldStartLayer(Visual visual) => false;
 
         private static IGeometryImpl? CreateLayerGeometryClip(VisualNode node)
         {

+ 2 - 3
src/Avalonia.Base/Rendering/SceneGraph/SceneLayer.cs

@@ -1,6 +1,5 @@
 using Avalonia.Media;
 using Avalonia.Platform;
-using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
@@ -14,7 +13,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         /// <param name="layerRoot">The visual at the root of the layer.</param>
         /// <param name="distanceFromRoot">The distance from the scene root.</param>
-        public SceneLayer(IVisual layerRoot, int distanceFromRoot)
+        public SceneLayer(Visual layerRoot, int distanceFromRoot)
         {
             LayerRoot = layerRoot;
             Dirty = new DirtyRects();
@@ -39,7 +38,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// <summary>
         /// Gets the visual at the root of the layer.
         /// </summary>
-        public IVisual LayerRoot { get; }
+        public Visual LayerRoot { get; }
 
         /// <summary>
         /// Gets the distance of the layer root from the root of the scene.

+ 11 - 11
src/Avalonia.Base/Rendering/SceneGraph/SceneLayers.cs

@@ -10,15 +10,15 @@ namespace Avalonia.Rendering.SceneGraph
     /// </summary>
     public class SceneLayers : IEnumerable<SceneLayer>
     {
-        private readonly IVisual _root;
+        private readonly Visual _root;
         private readonly List<SceneLayer> _inner;
-        private readonly Dictionary<IVisual, SceneLayer> _index;
+        private readonly Dictionary<Visual, SceneLayer> _index;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SceneLayers"/> class.
         /// </summary>
         /// <param name="root">The scene's root visual.</param>
-        public SceneLayers(IVisual root) : this(root, 0)
+        public SceneLayers(Visual root) : this(root, 0)
         {
         }
 
@@ -27,12 +27,12 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         /// <param name="root">The scene's root visual.</param>
         /// <param name="capacity">Initial layer capacity.</param>
-        public SceneLayers(IVisual root, int capacity)
+        public SceneLayers(Visual root, int capacity)
         {
             _root = root;
 
             _inner = new List<SceneLayer>(capacity);
-            _index = new Dictionary<IVisual, SceneLayer>(capacity);
+            _index = new Dictionary<Visual, SceneLayer>(capacity);
         }
 
         /// <summary>
@@ -71,14 +71,14 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         /// <param name="visual">The layer's root visual.</param>
         /// <returns>The layer.</returns>
-        public SceneLayer this[IVisual visual] => _index[visual];
+        public SceneLayer this[Visual visual] => _index[visual];
 
         /// <summary>
         /// Adds a layer to the scene.
         /// </summary>
         /// <param name="layerRoot">The root visual of the layer.</param>
         /// <returns>The created layer.</returns>
-        public SceneLayer Add(IVisual layerRoot)
+        public SceneLayer Add(Visual layerRoot)
         {
             _ = layerRoot ?? throw new ArgumentNullException(nameof(layerRoot));
 
@@ -115,7 +115,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// <returns>
         /// True if a layer exists with the specified root visual, otherwise false.
         /// </returns>
-        public bool Exists(IVisual layerRoot)
+        public bool Exists(Visual layerRoot)
         {
             _ = layerRoot ?? throw new ArgumentNullException(nameof(layerRoot));
 
@@ -127,7 +127,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         /// <param name="layerRoot">The root visual.</param>
         /// <returns>The layer if found, otherwise null.</returns>
-        public SceneLayer? Find(IVisual layerRoot)
+        public SceneLayer? Find(Visual layerRoot)
         {
             _index.TryGetValue(layerRoot, out var result);
             return result;
@@ -138,7 +138,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         /// <param name="layerRoot">The root visual.</param>
         /// <returns>The layer.</returns>
-        public SceneLayer GetOrAdd(IVisual layerRoot)
+        public SceneLayer GetOrAdd(Visual layerRoot)
         {
             _ = layerRoot ?? throw new ArgumentNullException(nameof(layerRoot));
 
@@ -155,7 +155,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         /// <param name="layerRoot">The root visual.</param>
         /// <returns>True if a matching layer was removed, otherwise false.</returns>
-        public bool Remove(IVisual layerRoot)
+        public bool Remove(Visual layerRoot)
         {
             _ = layerRoot ?? throw new ArgumentNullException(nameof(layerRoot));
 

+ 3 - 3
src/Avalonia.Base/Rendering/SceneGraph/VisualNode.cs

@@ -30,7 +30,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         /// <param name="visual">The visual that this node represents.</param>
         /// <param name="parent">The parent scene graph node, if any.</param>
-        public VisualNode(IVisual visual, IVisualNode? parent)
+        public VisualNode(Visual visual, IVisualNode? parent)
         {
             Visual = visual ?? throw new ArgumentNullException(nameof(visual));
             Parent = parent;
@@ -39,7 +39,7 @@ namespace Avalonia.Rendering.SceneGraph
         }
 
         /// <inheritdoc/>
-        public IVisual Visual { get; }
+        public Visual Visual { get; }
 
         /// <inheritdoc/>
         public IVisualNode? Parent { get; }
@@ -98,7 +98,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         public bool OpacityChanged { get; private set; }
 
-        public IVisual? LayerRoot { get; set; }
+        public Visual? LayerRoot { get; set; }
 
         /// <inheritdoc/>
         public IReadOnlyList<IVisualNode> Children => _children ?? EmptyChildren;

+ 3 - 3
src/Avalonia.Base/Rendering/ZIndexComparer.cs

@@ -4,11 +4,11 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering
 {
-    public class ZIndexComparer : IComparer<IVisual>
+    public class ZIndexComparer : IComparer<Visual>
     {
         public static readonly ZIndexComparer Instance = new ZIndexComparer();
-        public static readonly Comparison<IVisual> ComparisonInstance = Instance.Compare;
+        public static readonly Comparison<Visual> ComparisonInstance = Instance.Compare;
 
-        public int Compare(IVisual? x, IVisual? y) => (x?.ZIndex ?? 0).CompareTo(y?.ZIndex ?? 0);
+        public int Compare(Visual? x, Visual? y) => (x?.ZIndex ?? 0).CompareTo(y?.ZIndex ?? 0);
     }
 }

部分文件因文件數量過多而無法顯示