Browse Source

Merge branch 'master' into fix-filedialog-bugs

Jeremy Koritzinsky 7 năm trước cách đây
mục cha
commit
af7b456ca1
31 tập tin đã thay đổi với 496 bổ sung417 xóa
  1. 152 4
      .editorconfig
  2. 1 0
      Avalonia.sln
  3. 2 0
      readme.md
  4. 0 1
      src/Avalonia.Controls/Application.cs
  5. 1 1
      src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
  6. 1 1
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs
  7. 1 1
      src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
  8. 17 1
      src/Avalonia.Controls/TopLevel.cs
  9. 2 2
      src/Avalonia.Controls/Window.cs
  10. 2 3
      src/Avalonia.Controls/WindowBase.cs
  11. 5 0
      src/Avalonia.Layout/ILayoutRoot.cs
  12. 1 6
      src/Avalonia.Layout/LayoutManager.cs
  13. 3 7
      src/Avalonia.Layout/Layoutable.cs
  14. 0 5
      src/Avalonia.Themes.Default/MenuItem.xaml
  15. 1 1
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
  16. 3 11
      tests/Avalonia.Benchmarks/Layout/Measure.cs
  17. 12 6
      tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs
  18. 64 59
      tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
  19. 0 1
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
  20. 11 6
      tests/Avalonia.Controls.UnitTests/TopLevelTests.cs
  21. 1 1
      tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
  22. 3 4
      tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs
  23. 133 192
      tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs
  24. 40 47
      tests/Avalonia.Layout.UnitTests/LayoutableTests.cs
  25. 14 14
      tests/Avalonia.LeakTests/ControlTests.cs
  26. 2 2
      tests/Avalonia.UnitTests/TestRoot.cs
  27. 1 10
      tests/Avalonia.UnitTests/TestServices.cs
  28. 2 2
      tests/Avalonia.UnitTests/TestTemplatedRoot.cs
  29. 0 1
      tests/Avalonia.UnitTests/UnitTestApplication.cs
  30. 11 18
      tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs
  31. 10 10
      tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs

+ 152 - 4
.editorconfig

@@ -1,11 +1,159 @@
-; This file is for unifying the coding style for different editors and IDEs.
-; More information at http://EditorConfig.org
+# editorconfig.org
 
+# top-most EditorConfig file
 root = true
 
+# Default settings:
+# A newline ending every file
+# Use 4 spaces as indentation
 [*]
-end_of_line = CRLF
+insert_final_newline = true
+indent_style = space
+indent_size = 4
 
+# C# files
 [*.cs]
-indent_style = space
+# New line preferences
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_indent_labels = one_less_than_current
+
+# avoid this. unless absolutely necessary
+dotnet_style_qualification_for_field = false:suggestion
+dotnet_style_qualification_for_property = false:suggestion
+dotnet_style_qualification_for_method = false:suggestion
+dotnet_style_qualification_for_event = false:suggestion
+
+# prefer var
+csharp_style_var_for_built_in_types = true
+csharp_style_var_when_type_is_apparent = true
+csharp_style_var_elsewhere = true:suggestion
+
+# use language keywords instead of BCL types
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# name all constant fields using PascalCase
+dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols  = constant_fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.style    = pascal_case_style
+
+dotnet_naming_symbols.constant_fields.applicable_kinds   = field
+dotnet_naming_symbols.constant_fields.required_modifiers = const
+
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+# static fields should have s_ prefix
+dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
+dotnet_naming_rule.static_fields_should_have_prefix.symbols  = static_fields
+dotnet_naming_rule.static_fields_should_have_prefix.style    = static_prefix_style
+
+dotnet_naming_symbols.static_fields.applicable_kinds   = field
+dotnet_naming_symbols.static_fields.required_modifiers = static
+
+dotnet_naming_style.static_prefix_style.required_prefix = s_
+dotnet_naming_style.static_prefix_style.capitalization = camel_case 
+
+# internal and private fields should be _camelCase
+dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
+dotnet_naming_rule.camel_case_for_private_internal_fields.symbols  = private_internal_fields
+dotnet_naming_rule.camel_case_for_private_internal_fields.style    = camel_case_underscore_style
+
+dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
+dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
+
+dotnet_naming_style.camel_case_underscore_style.required_prefix = _
+dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case 
+
+# use accessibility modifiers
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
+
+# Code style defaults
+dotnet_sort_system_directives_first = true
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = false
+
+# Expression-level preferences
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+
+# Expression-bodied members
+csharp_style_expression_bodied_methods = false:none
+csharp_style_expression_bodied_constructors = false:none
+csharp_style_expression_bodied_operators = false:none
+csharp_style_expression_bodied_properties = true:none
+csharp_style_expression_bodied_indexers = true:none
+csharp_style_expression_bodied_accessors = true:none
+
+# Pattern matching
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+
+# Null checking preferences
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = do_not_ignore
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# Xaml files
+[*.xaml]
 indent_size = 4
+
+# Xml project files
+[*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
+indent_size = 2
+
+# Xml build files
+[*.builds]
+indent_size = 2
+
+# Xml files
+[*.{xml,stylecop,resx,ruleset}]
+indent_size = 2
+
+# Xml config files
+[*.{props,targets,config,nuspec}]
+indent_size = 2
+
+# Shell scripts
+[*.sh]
+end_of_line = lf
+[*.{cmd, bat}]
+end_of_line = crlf

+ 1 - 0
Avalonia.sln

@@ -58,6 +58,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{9B9E
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}"
 	ProjectSection(SolutionItems) = preProject
+		.editorconfig = .editorconfig
 		src\Shared\SharedAssemblyInfo.cs = src\Shared\SharedAssemblyInfo.cs
 	EndProjectSection
 EndProject

+ 2 - 0
readme.md

@@ -20,6 +20,8 @@ Avalonia is a WPF-inspired cross-platform XAML-based UI framework providing a fl
 
 Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started. After installing it, open "New Project" dialog in Visual Studio, choose "Avalonia" in "Visual C#" section, select "Avalonia .NET Core Application" and press OK (<a href="http://avaloniaui.net/docs/quickstart/images/new-project-dialog.png">screenshot</a>). Now you can write code and markup that will work on multiple platforms!
 
+For those without Visual Studio, starter guide for .NET Core CLI can be found [here](http://avaloniaui.net/docs/quickstart/create-new-project#net-core).
+
 Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: ([stable(ish)](https://www.nuget.org/packages/Avalonia/), [nightly](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed))
 
 Use these commands in Package Manager console to install Avalonia manually:

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

@@ -332,7 +332,6 @@ namespace Avalonia
                 .Bind<IInputManager>().ToConstant(InputManager)
                 .Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>()
                 .Bind<IStyler>().ToConstant(_styler)
-                .Bind<ILayoutManager>().ToSingleton<LayoutManager>()
                 .Bind<IApplicationLifecycle>().ToConstant(this)
                 .Bind<IScheduler>().ToConstant(AvaloniaScheduler.Instance)
                 .Bind<IDragDropDevice>().ToConstant(DragDropDevice.Instance)

+ 1 - 1
src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs

@@ -28,7 +28,7 @@ namespace Avalonia.Controls.Embedding
         {
             EnsureInitialized();
             ApplyTemplate();
-            LayoutManager.Instance.ExecuteInitialLayoutPass(this);
+            LayoutManager.ExecuteInitialLayoutPass(this);
         }
 
         private void EnsureInitialized()

+ 1 - 1
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs

@@ -22,7 +22,7 @@ namespace Avalonia.Controls.Embedding.Offscreen
         {
             EnsureInitialized();
             ApplyTemplate();
-            LayoutManager.Instance.ExecuteInitialLayoutPass(this);
+            LayoutManager.ExecuteInitialLayoutPass(this);
         }
 
         private void EnsureInitialized()

+ 1 - 1
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@@ -518,7 +518,7 @@ namespace Avalonia.Controls.Presenters
                 }
 
                 var container = generator.ContainerFromIndex(index);
-                var layoutManager = LayoutManager.Instance;
+                var layoutManager = (Owner.GetVisualRoot() as ILayoutRoot)?.LayoutManager;
 
                 // We need to do a layout here because it's possible that the container we moved to
                 // is only partially visible due to differing item sizes. If the container is only 

+ 17 - 1
src/Avalonia.Controls/TopLevel.cs

@@ -54,6 +54,7 @@ namespace Avalonia.Controls
         private readonly IApplicationLifecycle _applicationLifecycle;
         private readonly IPlatformRenderInterface _renderInterface;
         private Size _clientSize;
+        private ILayoutManager _layoutManager;
 
         /// <summary>
         /// Initializes static members of the <see cref="TopLevel"/> class.
@@ -147,6 +148,16 @@ namespace Avalonia.Controls
             protected set { SetAndRaise(ClientSizeProperty, ref _clientSize, value); }
         }
 
+        public ILayoutManager LayoutManager
+        {
+            get
+            {
+                if (_layoutManager == null)
+                    _layoutManager = CreateLayoutManager();
+                return _layoutManager;
+            }
+        }
+
         /// <summary>
         /// Gets the platform-specific window implementation.
         /// </summary>
@@ -235,6 +246,11 @@ namespace Avalonia.Controls
         {
             return PlatformImpl?.PointToScreen(p) ?? default(Point);
         }
+        
+        /// <summary>
+        /// Creates the layout manager for this <see cref="TopLevel" />.
+        /// </summary>
+        protected virtual ILayoutManager CreateLayoutManager() => new LayoutManager();
 
         /// <summary>
         /// Handles a paint notification from <see cref="ITopLevelImpl.Resized"/>.
@@ -267,7 +283,7 @@ namespace Avalonia.Controls
             ClientSize = clientSize;
             Width = clientSize.Width;
             Height = clientSize.Height;
-            LayoutManager.Instance.ExecuteLayoutPass();
+            LayoutManager.ExecuteLayoutPass();
             Renderer?.Resized(clientSize);
         }
 

+ 2 - 2
src/Avalonia.Controls/Window.cs

@@ -374,7 +374,7 @@ namespace Avalonia.Controls
 
             EnsureInitialized();
             IsVisible = true;
-            LayoutManager.Instance.ExecuteInitialLayoutPass(this);
+            LayoutManager.ExecuteInitialLayoutPass(this);
 
             using (BeginAutoSizing())
             {
@@ -416,7 +416,7 @@ namespace Avalonia.Controls
             EnsureInitialized();
             SetWindowStartupLocation();
             IsVisible = true;
-            LayoutManager.Instance.ExecuteInitialLayoutPass(this);
+            LayoutManager.ExecuteInitialLayoutPass(this);
 
             using (BeginAutoSizing())
             {

+ 2 - 3
src/Avalonia.Controls/WindowBase.cs

@@ -179,10 +179,9 @@ namespace Avalonia.Controls
 
                 if (!_hasExecutedInitialLayoutPass)
                 {
-                    LayoutManager.Instance.ExecuteInitialLayoutPass(this);
+                    LayoutManager.ExecuteInitialLayoutPass(this);
                     _hasExecutedInitialLayoutPass = true;
                 }
-
                 PlatformImpl?.Show();
                 Renderer?.Start();
             }
@@ -262,7 +261,7 @@ namespace Avalonia.Controls
                 Height = clientSize.Height;
             }
             ClientSize = clientSize;
-            LayoutManager.Instance.ExecuteLayoutPass();
+            LayoutManager.ExecuteLayoutPass();
             Renderer?.Resized(clientSize);
         }
 

+ 5 - 0
src/Avalonia.Layout/ILayoutRoot.cs

@@ -22,5 +22,10 @@ namespace Avalonia.Layout
         /// The scaling factor to use in layout.
         /// </summary>
         double LayoutScaling { get; }
+
+        /// <summary>
+        /// Associated instance of layout manager
+        /// </summary>
+        ILayoutManager LayoutManager { get; }
     }
 }

+ 1 - 6
src/Avalonia.Layout/LayoutManager.cs

@@ -19,11 +19,6 @@ namespace Avalonia.Layout
         private bool _queued;
         private bool _running;
 
-        /// <summary>
-        /// Gets the layout manager.
-        /// </summary>
-        public static ILayoutManager Instance => AvaloniaLocator.Current.GetService<ILayoutManager>();
-
         /// <inheritdoc/>
         public void InvalidateMeasure(ILayoutable control)
         {
@@ -170,7 +165,7 @@ namespace Avalonia.Layout
                 {
                     root.Measure(Size.Infinity);
                 }
-                else
+                else if (control.PreviousMeasure.HasValue)
                 {
                     control.Measure(control.PreviousMeasure.Value);
                 }

+ 3 - 7
src/Avalonia.Layout/Layoutable.cs

@@ -389,7 +389,7 @@ namespace Avalonia.Layout
 
                 if (((ILayoutable)this).IsAttachedToVisualTree)
                 {
-                    LayoutManager.Instance?.InvalidateMeasure(this);
+                    (VisualRoot as ILayoutRoot)?.LayoutManager.InvalidateMeasure(this);
                     InvalidateVisual();
                 }
                 OnMeasureInvalidated();
@@ -406,12 +406,8 @@ namespace Avalonia.Layout
                 Logger.Verbose(LogArea.Layout, this, "Invalidated arrange");
 
                 IsArrangeValid = false;
-
-                if (((ILayoutable)this).IsAttachedToVisualTree)
-                {
-                    LayoutManager.Instance?.InvalidateArrange(this);
-                    InvalidateVisual();
-                }
+                (VisualRoot as ILayoutRoot)?.LayoutManager?.InvalidateArrange(this);
+                InvalidateVisual();
             }
         }
 

+ 0 - 5
src/Avalonia.Themes.Default/MenuItem.xaml

@@ -122,11 +122,6 @@
     </Setter>
   </Style>
 
-  <Style Selector="MenuItem:selected /template/ Border#root">
-    <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
-    <Setter Property="BorderBrush" Value="{DynamicResource ThemeAccentBrush}"/>
-  </Style>
-
   <Style Selector="MenuItem:pointerover /template/ Border#root">
     <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
     <Setter Property="BorderBrush" Value="{DynamicResource ThemeAccentBrush}"/>

+ 1 - 1
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@@ -49,7 +49,7 @@ namespace Avalonia.Win32.Interop.Wpf
             protected override void HandleResized(Size clientSize)
             {
                 ClientSize = clientSize;
-                LayoutManager.Instance.ExecuteLayoutPass();
+                LayoutManager.ExecuteLayoutPass();
                 Renderer?.Resized(clientSize);
             }
 

+ 3 - 11
tests/Avalonia.Benchmarks/Layout/Measure.cs

@@ -8,26 +8,18 @@ using BenchmarkDotNet.Attributes;
 namespace Avalonia.Benchmarks.Layout
 {
     [MemoryDiagnoser]
-    public class Measure : IDisposable
+    public class Measure
     {
-        private IDisposable _app;
         private TestRoot root;
         private List<Control> controls = new List<Control>();
 
         public Measure()
         {
-            _app = UnitTestApplication.Start(TestServices.RealLayoutManager);
-
             var panel = new StackPanel();
             root = new TestRoot { Child = panel };
             controls.Add(panel);
             CreateChildren(panel, 3, 5);
-            LayoutManager.Instance.ExecuteInitialLayoutPass(root);
-        }
-
-        public void Dispose()
-        {
-            _app.Dispose();
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
         }
 
         [Benchmark]
@@ -43,7 +35,7 @@ namespace Avalonia.Benchmarks.Layout
                 }
             }
 
-            LayoutManager.Instance.ExecuteLayoutPass();
+            root.LayoutManager.ExecuteLayoutPass();
         }
 
         private void CreateChildren(IPanel parent, int childCount, int iterations)

+ 12 - 6
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs

@@ -12,6 +12,7 @@ using Avalonia.Layout;
 using Avalonia.Platform;
 using Avalonia.Rendering;
 using Avalonia.UnitTests;
+using Avalonia.VisualTree;
 using Xunit;
 
 namespace Avalonia.Controls.UnitTests.Presenters
@@ -219,13 +220,13 @@ namespace Avalonia.Controls.UnitTests.Presenters
         [Fact]
         public void Changing_VirtualizationMode_None_To_Simple_Should_Add_Correct_Number_Of_Controls()
         {
-            using (UnitTestApplication.Start(TestServices.RealLayoutManager))
+            using (UnitTestApplication.Start(new TestServices()))
             {
                 var target = CreateTarget(mode: ItemVirtualizationMode.None);
-                var scroll = (ScrollContentPresenter)target.Parent;
+                var scroll = (TestScroller)target.Parent;
 
-                scroll.Measure(new Size(100, 100));
-                scroll.Arrange(new Rect(0, 0, 100, 100));
+                scroll.Width = scroll.Height = 100;
+                scroll.LayoutManager.ExecuteInitialLayoutPass(scroll);
 
                 // Ensure than an intermediate measure pass doesn't add more controls than it
                 // should. This can happen if target gets measured with Size.Infinity which
@@ -237,7 +238,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
                 };
 
                 target.VirtualizationMode = ItemVirtualizationMode.Simple;
-                LayoutManager.Instance.ExecuteLayoutPass();
+                ((ILayoutRoot)scroll.GetVisualRoot()).LayoutManager.ExecuteLayoutPass();
 
                 Assert.Equal(10, target.Panel.Children.Count);
             }
@@ -315,12 +316,17 @@ namespace Avalonia.Controls.UnitTests.Presenters
             });
         }
 
-        private class TestScroller : ScrollContentPresenter, IRenderRoot
+        private class TestScroller : ScrollContentPresenter, IRenderRoot, ILayoutRoot
         {
             public IRenderer Renderer { get; }
             public Size ClientSize { get; }
             public double RenderScaling => 1;
 
+            public Size MaxClientSize => Size.Infinity;
+
+            public double LayoutScaling => 1;
+
+            public ILayoutManager LayoutManager { get; } = new LayoutManager();
             public IRenderTarget CreateRenderTarget()
             {
                 throw new NotImplementedException();

+ 64 - 59
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs

@@ -12,6 +12,7 @@ using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
 using Avalonia.Input;
+using Avalonia.Layout;
 using Avalonia.Platform;
 using Avalonia.Rendering;
 using Avalonia.UnitTests;
@@ -564,11 +565,10 @@ namespace Avalonia.Controls.UnitTests.Presenters
         [Fact]
         public void Scrolling_To_Item_In_Zero_Sized_Presenter_Doesnt_Throw()
         {
-            using (UnitTestApplication.Start(TestServices.RealLayoutManager))
+            using (UnitTestApplication.Start(new TestServices()))
             {
                 var target = CreateTarget(itemCount: 10);
                 var items = (IList<string>)target.Items;
-
                 target.ApplyTemplate();
                 target.Measure(Size.Empty);
                 target.Arrange(Rect.Empty);
@@ -723,10 +723,10 @@ namespace Avalonia.Controls.UnitTests.Presenters
             public void GetControlInDirection_Down_Should_Return_Existing_Container_If_Materialized()
             {
                 var target = CreateTarget();
+                var scroller = (TestScroller)target.Parent;
 
-                target.ApplyTemplate();
-                target.Measure(new Size(100, 100));
-                target.Arrange(new Rect(0, 0, 100, 100));
+                scroller.Width = scroller.Height = 100;
+                scroller.LayoutManager.ExecuteInitialLayoutPass(scroller);
 
                 var from = target.Panel.Children[5];
                 var result = ((ILogicalScrollable)target).GetControlInDirection(
@@ -740,10 +740,10 @@ namespace Avalonia.Controls.UnitTests.Presenters
             public void GetControlInDirection_Down_Should_Scroll_If_Necessary()
             {
                 var target = CreateTarget();
+                var scroller = (TestScroller)target.Parent;
 
-                target.ApplyTemplate();
-                target.Measure(new Size(100, 100));
-                target.Arrange(new Rect(0, 0, 100, 100));
+                scroller.Width = scroller.Height = 100;
+                scroller.LayoutManager.ExecuteInitialLayoutPass(scroller);
 
                 var from = target.Panel.Children[9];
                 var result = ((ILogicalScrollable)target).GetControlInDirection(
@@ -757,44 +757,40 @@ namespace Avalonia.Controls.UnitTests.Presenters
             [Fact]
             public void GetControlInDirection_Down_Should_Scroll_If_Partially_Visible()
             {
-                using (UnitTestApplication.Start(TestServices.RealLayoutManager))
-                {
-                    var target = CreateTarget();
-                    var scroller = (ScrollContentPresenter)target.Parent;
+                var target = CreateTarget();
+                var scroller = (TestScroller)target.Parent;
 
-                    scroller.Measure(new Size(100, 95));
-                    scroller.Arrange(new Rect(0, 0, 100, 95));
+                scroller.Width = 100;
+                scroller.Height = 95;
+                scroller.LayoutManager.ExecuteInitialLayoutPass(scroller);
 
-                    var from = target.Panel.Children[8];
-                    var result = ((ILogicalScrollable)target).GetControlInDirection(
-                        NavigationDirection.Down,
-                        from);
+                var from = target.Panel.Children[8];
+                var result = ((ILogicalScrollable)target).GetControlInDirection(
+                    NavigationDirection.Down,
+                    from);
 
-                    Assert.Equal(new Vector(0, 1), ((ILogicalScrollable)target).Offset);
-                    Assert.Same(target.Panel.Children[8], result);
-                }
+                Assert.Equal(new Vector(0, 1), ((ILogicalScrollable)target).Offset);
+                Assert.Same(target.Panel.Children[8], result);
             }
 
             [Fact]
             public void GetControlInDirection_Up_Should_Scroll_If_Partially_Visible_Item_Is_Currently_Shown()
             {
-                using (UnitTestApplication.Start(TestServices.RealLayoutManager))
-                {
-                    var target = CreateTarget();
-                    var scroller = (ScrollContentPresenter)target.Parent;
+                var target = CreateTarget();
+                var scroller = (TestScroller)target.Parent;
 
-                    scroller.Measure(new Size(100, 95));
-                    scroller.Arrange(new Rect(0, 0, 100, 95));
-                    ((ILogicalScrollable)target).Offset = new Vector(0, 11);
+                scroller.Width = 100;
+                scroller.Height = 95;
+                scroller.LayoutManager.ExecuteInitialLayoutPass(scroller);
+                ((ILogicalScrollable)target).Offset = new Vector(0, 11);
 
-                    var from = target.Panel.Children[1];
-                    var result = ((ILogicalScrollable)target).GetControlInDirection(
-                        NavigationDirection.Up,
-                        from);
+                var from = target.Panel.Children[1];
+                var result = ((ILogicalScrollable)target).GetControlInDirection(
+                    NavigationDirection.Up,
+                    from);
 
-                    Assert.Equal(new Vector(0, 10), ((ILogicalScrollable)target).Offset);
-                    Assert.Same(target.Panel.Children[0], result);
-                }
+                Assert.Equal(new Vector(0, 10), ((ILogicalScrollable)target).Offset);
+                Assert.Same(target.Panel.Children[0], result);
             }
 
             [Fact]
@@ -835,10 +831,10 @@ namespace Avalonia.Controls.UnitTests.Presenters
             public void GetControlInDirection_Right_Should_Return_Existing_Container_If_Materialized()
             {
                 var target = CreateTarget(orientation: Orientation.Horizontal);
+                var scroller = (TestScroller)target.Parent;
 
-                target.ApplyTemplate();
-                target.Measure(new Size(100, 100));
-                target.Arrange(new Rect(0, 0, 100, 100));
+                scroller.Width = scroller.Height = 100;
+                scroller.LayoutManager.ExecuteInitialLayoutPass(scroller);
 
                 var from = target.Panel.Children[5];
                 var result = ((ILogicalScrollable)target).GetControlInDirection(
@@ -852,10 +848,10 @@ namespace Avalonia.Controls.UnitTests.Presenters
             public void GetControlInDirection_Right_Should_Scroll_If_Necessary()
             {
                 var target = CreateTarget(orientation: Orientation.Horizontal);
+                var scroller = (TestScroller)target.Parent;
 
-                target.ApplyTemplate();
-                target.Measure(new Size(100, 100));
-                target.Arrange(new Rect(0, 0, 100, 100));
+                scroller.Width = scroller.Height = 100;
+                scroller.LayoutManager.ExecuteInitialLayoutPass(scroller);
 
                 var from = target.Panel.Children[9];
                 var result = ((ILogicalScrollable)target).GetControlInDirection(
@@ -869,32 +865,31 @@ namespace Avalonia.Controls.UnitTests.Presenters
             [Fact]
             public void GetControlInDirection_Right_Should_Scroll_If_Partially_Visible()
             {
-                using (UnitTestApplication.Start(TestServices.RealLayoutManager))
-                {
-                    var target = CreateTarget(orientation: Orientation.Horizontal);
-                    var scroller = (ScrollContentPresenter)target.Parent;
+                var target = CreateTarget(orientation: Orientation.Horizontal);
+                var scroller = (TestScroller)target.Parent;
 
-                    scroller.Measure(new Size(95, 100));
-                    scroller.Arrange(new Rect(0, 0, 95, 100));
+                scroller.Width = 95;
+                scroller.Height = 100;
+                scroller.LayoutManager.ExecuteInitialLayoutPass(scroller);
 
-                    var from = target.Panel.Children[8];
-                    var result = ((ILogicalScrollable)target).GetControlInDirection(
-                        NavigationDirection.Right,
-                        from);
+                var from = target.Panel.Children[8];
+                var result = ((ILogicalScrollable)target).GetControlInDirection(
+                    NavigationDirection.Right,
+                    from);
 
-                    Assert.Equal(new Vector(1, 0), ((ILogicalScrollable)target).Offset);
-                    Assert.Same(target.Panel.Children[8], result);
-                }
+                Assert.Equal(new Vector(1, 0), ((ILogicalScrollable)target).Offset);
+                Assert.Same(target.Panel.Children[8], result);
             }
 
             [Fact]
             public void GetControlInDirection_Left_Should_Scroll_If_Partially_Visible_Item_Is_Currently_Shown()
             {
                 var target = CreateTarget(orientation: Orientation.Horizontal);
+                var scroller = (TestScroller)target.Parent;
 
-                target.ApplyTemplate();
-                target.Measure(new Size(95, 100));
-                target.Arrange(new Rect(0, 0, 95, 100));
+                scroller.Width = 95;
+                scroller.Height = 100;
+                scroller.LayoutManager.ExecuteInitialLayoutPass(scroller);
                 ((ILogicalScrollable)target).Offset = new Vector(11, 0);
 
                 var from = target.Panel.Children[1];
@@ -1010,7 +1005,6 @@ namespace Avalonia.Controls.UnitTests.Presenters
             };
 
             scroller.UpdateChild();
-
             return result;
         }
 
@@ -1032,12 +1026,18 @@ namespace Avalonia.Controls.UnitTests.Presenters
             });
         }
 
-        private class TestScroller : ScrollContentPresenter, IRenderRoot
+        private class TestScroller : ScrollContentPresenter, IRenderRoot, ILayoutRoot
         {
             public IRenderer Renderer { get; }
             public Size ClientSize { get; }
             public double RenderScaling => 1;
 
+            public Size MaxClientSize => Size.Infinity;
+
+            public double LayoutScaling => 1;
+
+            public ILayoutManager LayoutManager { get; } = new LayoutManager();
+
             public IRenderTarget CreateRenderTarget()
             {
                 throw new NotImplementedException();
@@ -1057,6 +1057,11 @@ namespace Avalonia.Controls.UnitTests.Presenters
             {
                 throw new NotImplementedException();
             }
+
+            protected override Size MeasureOverride(Size availableSize)
+            {
+                return base.MeasureOverride(availableSize);
+            }
         }
 
         private class TestItemsPresenter : ItemsPresenter

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

@@ -306,7 +306,6 @@ namespace Avalonia.Controls.UnitTests.Primitives
             var renderInterface = new Mock<IPlatformRenderInterface>();
 
             AvaloniaLocator.CurrentMutable
-                .Bind<ILayoutManager>().ToTransient<LayoutManager>()
                 .Bind<IGlobalStyles>().ToFunc(() => globalStyles.Object)
                 .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
                 .Bind<IStyler>().ToTransient<Styler>()

+ 11 - 6
tests/Avalonia.Controls.UnitTests/TopLevelTests.cs

@@ -74,15 +74,16 @@ namespace Avalonia.Controls.UnitTests
         [Fact]
         public void Layout_Pass_Should_Not_Be_Automatically_Scheduled()
         {
-            var services = TestServices.StyledWindow.With(layoutManager: Mock.Of<ILayoutManager>());
+            var services = TestServices.StyledWindow;
 
             using (UnitTestApplication.Start(services))
             {
                 var impl = new Mock<ITopLevelImpl>();
-                var target = new TestTopLevel(impl.Object);
+                
+                var target = new TestTopLevel(impl.Object, Mock.Of<ILayoutManager>());
 
                 // The layout pass should be scheduled by the derived class.
-                var layoutManagerMock = Mock.Get(LayoutManager.Instance);
+                var layoutManagerMock = Mock.Get(target.LayoutManager);
                 layoutManagerMock.Verify(x => x.ExecuteLayoutPass(), Times.Never);
             }
         }
@@ -107,7 +108,7 @@ namespace Avalonia.Controls.UnitTests
                     }
                 };
 
-                LayoutManager.Instance.ExecuteInitialLayoutPass(target);
+                target.LayoutManager.ExecuteInitialLayoutPass(target);
 
                 Assert.Equal(new Rect(0, 0, 321, 432), target.Bounds);
             }
@@ -122,7 +123,7 @@ namespace Avalonia.Controls.UnitTests
                 impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
 
                 var target = new TestTopLevel(impl.Object);
-                LayoutManager.Instance.ExecuteLayoutPass();
+                target.LayoutManager.ExecuteLayoutPass();
 
                 Assert.Equal(double.NaN, target.Width);
                 Assert.Equal(double.NaN, target.Height);
@@ -248,13 +249,17 @@ namespace Avalonia.Controls.UnitTests
 
         private class TestTopLevel : TopLevel
         {
+            private readonly ILayoutManager _layoutManager;
             public bool IsClosed { get; private set; }
 
-            public TestTopLevel(ITopLevelImpl impl)
+            public TestTopLevel(ITopLevelImpl impl, ILayoutManager layoutManager = null)
                 : base(impl)
             {
+                _layoutManager = layoutManager ?? new LayoutManager();
             }
 
+            protected override ILayoutManager CreateLayoutManager() => _layoutManager;
+
             protected override void HandleApplicationExiting()
             {
                 base.HandleApplicationExiting();

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

@@ -40,7 +40,7 @@ namespace Avalonia.Controls.UnitTests
                     IsVisible = true,
                 };
 
-                LayoutManager.Instance.ExecuteInitialLayoutPass(target);
+                target.LayoutManager.ExecuteInitialLayoutPass(target);
 
                 Mock.Get(impl).Verify(x => x.Resize(new Size(321, 432)));
             }

+ 3 - 4
tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

@@ -57,11 +57,11 @@ namespace Avalonia.Layout.UnitTests
                 };
 
                 window.Show();
-                LayoutManager.Instance.ExecuteInitialLayoutPass(window);
+                window.LayoutManager.ExecuteInitialLayoutPass(window);
 
                 Assert.Equal(new Size(400, 400), border.Bounds.Size);
                 textBlock.Width = 200;
-                LayoutManager.Instance.ExecuteLayoutPass();
+                window.LayoutManager.ExecuteLayoutPass();
 
                 Assert.Equal(new Size(200, 400), border.Bounds.Size);
             }
@@ -99,7 +99,7 @@ namespace Avalonia.Layout.UnitTests
                 };
 
                 window.Show();
-                LayoutManager.Instance.ExecuteInitialLayoutPass(window);
+                window.LayoutManager.ExecuteInitialLayoutPass(window);
 
                 Assert.Equal(new Size(800, 600), window.Bounds.Size);
                 Assert.Equal(new Size(200, 200), scrollViewer.Bounds.Size);
@@ -200,7 +200,6 @@ namespace Avalonia.Layout.UnitTests
                 .Bind<IAssetLoader>().ToConstant(new AssetLoader())
                 .Bind<IInputManager>().ToConstant(new Mock<IInputManager>().Object)
                 .Bind<IGlobalStyles>().ToConstant(globalStyles.Object)
-                .Bind<ILayoutManager>().ToConstant(new LayoutManager())
                 .Bind<IRuntimePlatform>().ToConstant(new AppBuilder().RuntimePlatform)
                 .Bind<IPlatformRenderInterface>().ToConstant(renderInterface.Object)
                 .Bind<IStyler>().ToConstant(new Styler())

+ 133 - 192
tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs

@@ -14,290 +14,231 @@ namespace Avalonia.Layout.UnitTests
         [Fact]
         public void Measures_And_Arranges_InvalidateMeasured_Control()
         {
-            var target = new LayoutManager();
+            var control = new LayoutTestControl();
+            var root = new LayoutTestRoot { Child = control };
 
-            using (Start(target))
-            {
-                var control = new LayoutTestControl();
-                var root = new LayoutTestRoot { Child = control };
-
-                target.ExecuteInitialLayoutPass(root);
-                control.Measured = control.Arranged = false;
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+            control.Measured = control.Arranged = false;
 
-                control.InvalidateMeasure();
-                target.ExecuteLayoutPass();
+            control.InvalidateMeasure();
+            root.LayoutManager.ExecuteLayoutPass();
 
-                Assert.True(control.Measured);
-                Assert.True(control.Arranged);
-            }
+            Assert.True(control.Measured);
+            Assert.True(control.Arranged);
         }
 
         [Fact]
         public void Arranges_InvalidateArranged_Control()
         {
-            var target = new LayoutManager();
+            var control = new LayoutTestControl();
+            var root = new LayoutTestRoot { Child = control };
 
-            using (Start(target))
-            {
-                var control = new LayoutTestControl();
-                var root = new LayoutTestRoot { Child = control };
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+            control.Measured = control.Arranged = false;
 
-                target.ExecuteInitialLayoutPass(root);
-                control.Measured = control.Arranged = false;
+            control.InvalidateArrange();
+            root.LayoutManager.ExecuteLayoutPass();
 
-                control.InvalidateArrange();
-                target.ExecuteLayoutPass();
-
-                Assert.False(control.Measured);
-                Assert.True(control.Arranged);
-            }
+            Assert.False(control.Measured);
+            Assert.True(control.Arranged);
         }
 
         [Fact]
         public void Measures_Parent_Of_Newly_Added_Control()
         {
-            var target = new LayoutManager();
-
-            using (Start(target))
-            {
-                var control = new LayoutTestControl();
-                var root = new LayoutTestRoot();
+            var control = new LayoutTestControl();
+            var root = new LayoutTestRoot();
 
-                target.ExecuteInitialLayoutPass(root);
-                root.Child = control;
-                root.Measured = root.Arranged = false;
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+            root.Child = control;
+            root.Measured = root.Arranged = false;
 
-                target.ExecuteLayoutPass();
+            root.LayoutManager.ExecuteLayoutPass();
 
-                Assert.True(root.Measured);
-                Assert.True(root.Arranged);
-                Assert.True(control.Measured);
-                Assert.True(control.Arranged);
-            }
+            Assert.True(root.Measured);
+            Assert.True(root.Arranged);
+            Assert.True(control.Measured);
+            Assert.True(control.Arranged);
         }
 
         [Fact]
         public void Measures_In_Correct_Order()
         {
-            var target = new LayoutManager();
-
-            using (Start(target))
+            LayoutTestControl control1;
+            LayoutTestControl control2;
+            var root = new LayoutTestRoot
             {
-                LayoutTestControl control1;
-                LayoutTestControl control2;
-                var root = new LayoutTestRoot
+                Child = control1 = new LayoutTestControl
                 {
-                    Child = control1 = new LayoutTestControl
-                    {
-                        Child = control2 = new LayoutTestControl(),
-                    }
-                };
+                    Child = control2 = new LayoutTestControl(),
+                }
+            };
 
 
-                var order = new List<ILayoutable>();
-                Size MeasureOverride(ILayoutable control, Size size)
-                {
-                    order.Add(control);
-                    return new Size(10, 10);
-                }
+            var order = new List<ILayoutable>();
+            Size MeasureOverride(ILayoutable control, Size size)
+            {
+                order.Add(control);
+                return new Size(10, 10);
+            }
 
-                root.DoMeasureOverride = MeasureOverride;
-                control1.DoMeasureOverride = MeasureOverride;
-                control2.DoMeasureOverride = MeasureOverride;
-                target.ExecuteInitialLayoutPass(root);
+            root.DoMeasureOverride = MeasureOverride;
+            control1.DoMeasureOverride = MeasureOverride;
+            control2.DoMeasureOverride = MeasureOverride;
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
 
-                control2.InvalidateMeasure();
-                control1.InvalidateMeasure();
-                root.InvalidateMeasure();
+            control2.InvalidateMeasure();
+            control1.InvalidateMeasure();
+            root.InvalidateMeasure();
 
-                order.Clear();
-                target.ExecuteLayoutPass();
+            order.Clear();
+            root.LayoutManager.ExecuteLayoutPass();
 
-                Assert.Equal(new ILayoutable[] { root, control1, control2 }, order);
-            }
+            Assert.Equal(new ILayoutable[] { root, control1, control2 }, order);
         }
 
         [Fact]
         public void Measures_Root_And_Grandparent_In_Correct_Order()
         {
-            var target = new LayoutManager();
-
-            using (Start(target))
+            LayoutTestControl control1;
+            LayoutTestControl control2;
+            var root = new LayoutTestRoot
             {
-                LayoutTestControl control1;
-                LayoutTestControl control2;
-                var root = new LayoutTestRoot
+                Child = control1 = new LayoutTestControl
                 {
-                    Child = control1 = new LayoutTestControl
-                    {
-                        Child = control2 = new LayoutTestControl(),
-                    }
-                };
+                    Child = control2 = new LayoutTestControl(),
+                }
+            };
 
 
-                var order = new List<ILayoutable>();
-                Size MeasureOverride(ILayoutable control, Size size)
-                {
-                    order.Add(control);
-                    return new Size(10, 10);
-                }
+            var order = new List<ILayoutable>();
+            Size MeasureOverride(ILayoutable control, Size size)
+            {
+                order.Add(control);
+                return new Size(10, 10);
+            }
 
-                root.DoMeasureOverride = MeasureOverride;
-                control1.DoMeasureOverride = MeasureOverride;
-                control2.DoMeasureOverride = MeasureOverride;
-                target.ExecuteInitialLayoutPass(root);
+            root.DoMeasureOverride = MeasureOverride;
+            control1.DoMeasureOverride = MeasureOverride;
+            control2.DoMeasureOverride = MeasureOverride;
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
 
-                control2.InvalidateMeasure();
-                root.InvalidateMeasure();
+            control2.InvalidateMeasure();
+            root.InvalidateMeasure();
 
-                order.Clear();
-                target.ExecuteLayoutPass();
+            order.Clear();
+            root.LayoutManager.ExecuteLayoutPass();
 
-                Assert.Equal(new ILayoutable[] { root, control2 }, order);
-            }
+            Assert.Equal(new ILayoutable[] { root, control2 }, order);
         }
 
         [Fact]
         public void Doesnt_Measure_Non_Invalidated_Root()
         {
-            var target = new LayoutManager();
+            var control = new LayoutTestControl();
+            var root = new LayoutTestRoot { Child = control };
 
-            using (Start(target))
-            {
-                var control = new LayoutTestControl();
-                var root = new LayoutTestRoot { Child = control };
-
-                target.ExecuteInitialLayoutPass(root);
-                root.Measured = root.Arranged = false;
-                control.Measured = control.Arranged = false;
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+            root.Measured = root.Arranged = false;
+            control.Measured = control.Arranged = false;
 
-                control.InvalidateMeasure();
-                target.ExecuteLayoutPass();
+            control.InvalidateMeasure();
+            root.LayoutManager.ExecuteLayoutPass();
 
-                Assert.False(root.Measured);
-                Assert.False(root.Arranged);
-                Assert.True(control.Measured);
-                Assert.True(control.Arranged);
-            }
+            Assert.False(root.Measured);
+            Assert.False(root.Arranged);
+            Assert.True(control.Measured);
+            Assert.True(control.Arranged);
         }
 
         [Fact]
         public void Doesnt_Measure_Removed_Control()
         {
-            var target = new LayoutManager();
+            var control = new LayoutTestControl();
+            var root = new LayoutTestRoot { Child = control };
 
-            using (Start(target))
-            {
-                var control = new LayoutTestControl();
-                var root = new LayoutTestRoot { Child = control };
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+            control.Measured = control.Arranged = false;
 
-                target.ExecuteInitialLayoutPass(root);
-                control.Measured = control.Arranged = false;
+            control.InvalidateMeasure();
+            root.Child = null;
+            root.LayoutManager.ExecuteLayoutPass();
 
-                control.InvalidateMeasure();
-                root.Child = null;
-                target.ExecuteLayoutPass();
-
-                Assert.False(control.Measured);
-                Assert.False(control.Arranged);
-            }
+            Assert.False(control.Measured);
+            Assert.False(control.Arranged);
         }
 
         [Fact]
         public void Measures_Root_With_Infinity()
         {
-            var target = new LayoutManager();
+            var root = new LayoutTestRoot();
+            var availableSize = default(Size);
 
-            using (Start(target))
-            {
-                var root = new LayoutTestRoot();
-                var availableSize = default(Size);
+            // Should not measure with this size.
+            root.MaxClientSize = new Size(123, 456);
 
-                // Should not measure with this size.
-                root.MaxClientSize = new Size(123, 456);
-
-                root.DoMeasureOverride = (_, s) =>
-                {
-                    availableSize = s;
-                    return new Size(100, 100);
-                };
+            root.DoMeasureOverride = (_, s) =>
+            {
+                availableSize = s;
+                return new Size(100, 100);
+            };
 
-                target.ExecuteInitialLayoutPass(root);
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
 
-                Assert.Equal(Size.Infinity, availableSize);
-            }
+            Assert.Equal(Size.Infinity, availableSize);
         }
 
         [Fact]
         public void Arranges_Root_With_DesiredSize()
         {
-            var target = new LayoutManager();
- 
-            using (Start(target))
+            var root = new LayoutTestRoot
             {
-                var root = new LayoutTestRoot
-                {
-                    Width = 100,
-                    Height = 100,
-                };
+                Width = 100,
+                Height = 100,
+            };
  
-                var arrangeSize = default(Size);
+            var arrangeSize = default(Size);
  
-                root.DoArrangeOverride = (_, s) =>
-                {
-                    arrangeSize = s;
-                    return s;
-                };
- 
-                target.ExecuteInitialLayoutPass(root);
-                Assert.Equal(new Size(100, 100), arrangeSize);
- 
-                root.Width = 120;
+            root.DoArrangeOverride = (_, s) =>
+            {
+                arrangeSize = s;
+                return s;
+            };
+
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+            Assert.Equal(new Size(100, 100), arrangeSize);
  
-                target.ExecuteLayoutPass();
-                Assert.Equal(new Size(120, 100), arrangeSize);
-            }
+            root.Width = 120;
+
+            root.LayoutManager.ExecuteLayoutPass();
+            Assert.Equal(new Size(120, 100), arrangeSize);
         }
 
         [Fact]
         public void Invalidating_Child_Remeasures_Parent()
         {
-            var target = new LayoutManager();
+            Border border;
+            StackPanel panel;
 
-            using (Start(target))
+            var root = new LayoutTestRoot
             {
-                AvaloniaLocator.CurrentMutable.Bind<ILayoutManager>().ToConstant(target);
-
-                Border border;
-                StackPanel panel;
-
-                var root = new LayoutTestRoot
+                Child = panel = new StackPanel
                 {
-                    Child = panel = new StackPanel
+                    Children =
                     {
-                        Children =
-                        {
-                            (border = new Border())
-                        }
+                        (border = new Border())
                     }
-                };
-
-                target.ExecuteInitialLayoutPass(root);
-                Assert.Equal(new Size(0, 0), root.DesiredSize);
+                }
+            };
 
-                border.Width = 100;
-                border.Height = 100;
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+            Assert.Equal(new Size(0, 0), root.DesiredSize);
 
-                target.ExecuteLayoutPass();
-                Assert.Equal(new Size(100, 100), panel.DesiredSize);
-            }                
-        }
+            border.Width = 100;
+            border.Height = 100;
 
-        private IDisposable Start(LayoutManager layoutManager)
-        {
-            var result = AvaloniaLocator.EnterScope();
-            AvaloniaLocator.CurrentMutable.Bind<ILayoutManager>().ToConstant(layoutManager);
-            return result;
+            root.LayoutManager.ExecuteLayoutPass();
+            Assert.Equal(new Size(100, 100), panel.DesiredSize);             
         }
     }
 }

+ 40 - 47
tests/Avalonia.Layout.UnitTests/LayoutableTests.cs

@@ -102,80 +102,73 @@ namespace Avalonia.Layout.UnitTests
         public void Only_Calls_LayoutManager_InvalidateMeasure_Once()
         {
             var target = new Mock<ILayoutManager>();
-
-            using (Start(target.Object))
+            var control = new Decorator();
+            var root = new LayoutTestRoot
             {
-                var control = new Decorator();
-                var root = new LayoutTestRoot { Child = control };
+                Child = control,
+                LayoutManager = target.Object,
+            };
 
-                root.Measure(Size.Infinity);
-                root.Arrange(new Rect(root.DesiredSize));
-                target.ResetCalls();
+            root.Measure(Size.Infinity);
+            root.Arrange(new Rect(root.DesiredSize));
+            target.ResetCalls();
 
-                control.InvalidateMeasure();
-                control.InvalidateMeasure();
+            control.InvalidateMeasure();
+            control.InvalidateMeasure();
 
-                target.Verify(x => x.InvalidateMeasure(control), Times.Once());
-            }
+            target.Verify(x => x.InvalidateMeasure(control), Times.Once());
         }
 
         [Fact]
         public void Only_Calls_LayoutManager_InvalidateArrange_Once()
         {
             var target = new Mock<ILayoutManager>();
-
-            using (Start(target.Object))
+            var control = new Decorator();
+            var root = new LayoutTestRoot
             {
-                var control = new Decorator();
-                var root = new LayoutTestRoot { Child = control };
+                Child = control,
+                LayoutManager = target.Object,
+            };
 
-                root.Measure(Size.Infinity);
-                root.Arrange(new Rect(root.DesiredSize));
-                target.ResetCalls();
+            root.Measure(Size.Infinity);
+            root.Arrange(new Rect(root.DesiredSize));
+            target.ResetCalls();
 
-                control.InvalidateArrange();
-                control.InvalidateArrange();
+            control.InvalidateArrange();
+            control.InvalidateArrange();
 
-                target.Verify(x => x.InvalidateArrange(control), Times.Once());
-            }
+            target.Verify(x => x.InvalidateArrange(control), Times.Once());
         }
 
         [Fact]
         public void Attaching_Control_To_Tree_Invalidates_Parent_Measure()
         {
             var target = new Mock<ILayoutManager>();
-
-            using (Start(target.Object))
+            var control = new Decorator();
+            var root = new LayoutTestRoot
             {
-                var control = new Decorator();
-                var root = new LayoutTestRoot { Child = control };
-
-                root.Measure(Size.Infinity);
-                root.Arrange(new Rect(root.DesiredSize));
-                Assert.True(control.IsMeasureValid);
+                Child = control,
+                LayoutManager = target.Object,
+            };
 
-                root.Child = null;
-                root.Measure(Size.Infinity);
-                root.Arrange(new Rect(root.DesiredSize));
+            root.Measure(Size.Infinity);
+            root.Arrange(new Rect(root.DesiredSize));
+            Assert.True(control.IsMeasureValid);
 
-                Assert.False(control.IsMeasureValid);
-                Assert.True(root.IsMeasureValid);
+            root.Child = null;
+            root.Measure(Size.Infinity);
+            root.Arrange(new Rect(root.DesiredSize));
 
-                target.ResetCalls();
+            Assert.False(control.IsMeasureValid);
+            Assert.True(root.IsMeasureValid);
 
-                root.Child = control;
+            target.ResetCalls();
 
-                Assert.False(root.IsMeasureValid);
-                Assert.False(control.IsMeasureValid);
-                target.Verify(x => x.InvalidateMeasure(root), Times.Once());
-            }
-        }
+            root.Child = control;
 
-        private IDisposable Start(ILayoutManager layoutManager)
-        {
-            var result = AvaloniaLocator.EnterScope();
-            AvaloniaLocator.CurrentMutable.Bind<ILayoutManager>().ToConstant(layoutManager);
-            return result;
+            Assert.False(root.IsMeasureValid);
+            Assert.False(control.IsMeasureValid);
+            target.Verify(x => x.InvalidateMeasure(root), Times.Once());
         }
 
         private class TestLayoutable : Layoutable

+ 14 - 14
tests/Avalonia.LeakTests/ControlTests.cs

@@ -42,12 +42,12 @@ namespace Avalonia.LeakTests
                     window.Show();
 
                     // Do a layout and make sure that Canvas gets added to visual tree.
-                    LayoutManager.Instance.ExecuteInitialLayoutPass(window);
+                    window.LayoutManager.ExecuteInitialLayoutPass(window);
                     Assert.IsType<Canvas>(window.Presenter.Child);
 
                     // Clear the content and ensure the Canvas is removed.
                     window.Content = null;
-                    LayoutManager.Instance.ExecuteLayoutPass();
+                    window.LayoutManager.ExecuteLayoutPass();
                     Assert.Null(window.Presenter.Child);
 
                     return window;
@@ -78,13 +78,13 @@ namespace Avalonia.LeakTests
                     window.Show();
 
                     // Do a layout and make sure that Canvas gets added to visual tree.
-                    LayoutManager.Instance.ExecuteInitialLayoutPass(window);
+                    window.LayoutManager.ExecuteInitialLayoutPass(window);
                     Assert.IsType<Canvas>(window.Find<Canvas>("foo"));
                     Assert.IsType<Canvas>(window.Presenter.Child);
 
                     // Clear the content and ensure the Canvas is removed.
                     window.Content = null;
-                    LayoutManager.Instance.ExecuteLayoutPass();
+                    window.LayoutManager.ExecuteLayoutPass();
                     Assert.Null(window.Presenter.Child);
 
                     return window;
@@ -116,13 +116,13 @@ namespace Avalonia.LeakTests
 
                     // Do a layout and make sure that ScrollViewer gets added to visual tree and its 
                     // template applied.
-                    LayoutManager.Instance.ExecuteInitialLayoutPass(window);
+                    window.LayoutManager.ExecuteInitialLayoutPass(window);
                     Assert.IsType<ScrollViewer>(window.Presenter.Child);
                     Assert.IsType<Canvas>(((ScrollViewer)window.Presenter.Child).Presenter.Child);
 
                     // Clear the content and ensure the ScrollViewer is removed.
                     window.Content = null;
-                    LayoutManager.Instance.ExecuteLayoutPass();
+                    window.LayoutManager.ExecuteLayoutPass();
                     Assert.Null(window.Presenter.Child);
 
                     return window;
@@ -153,13 +153,13 @@ namespace Avalonia.LeakTests
 
                     // Do a layout and make sure that TextBox gets added to visual tree and its 
                     // template applied.
-                    LayoutManager.Instance.ExecuteInitialLayoutPass(window);
+                    window.LayoutManager.ExecuteInitialLayoutPass(window);
                     Assert.IsType<TextBox>(window.Presenter.Child);
                     Assert.NotEmpty(window.Presenter.Child.GetVisualChildren());
 
                     // Clear the content and ensure the TextBox is removed.
                     window.Content = null;
-                    LayoutManager.Instance.ExecuteLayoutPass();
+                    window.LayoutManager.ExecuteLayoutPass();
                     Assert.Null(window.Presenter.Child);
 
                     return window;
@@ -197,14 +197,14 @@ namespace Avalonia.LeakTests
 
                     // Do a layout and make sure that TextBox gets added to visual tree and its 
                     // Text property set.
-                    LayoutManager.Instance.ExecuteInitialLayoutPass(window);
+                    window.LayoutManager.ExecuteInitialLayoutPass(window);
                     Assert.IsType<TextBox>(window.Presenter.Child);
                     Assert.Equal("foo", ((TextBox)window.Presenter.Child).Text);
 
                     // Clear the content and DataContext and ensure the TextBox is removed.
                     window.Content = null;
                     window.DataContext = null;
-                    LayoutManager.Instance.ExecuteLayoutPass();
+                    window.LayoutManager.ExecuteLayoutPass();
                     Assert.Null(window.Presenter.Child);
 
                     return window;
@@ -235,7 +235,7 @@ namespace Avalonia.LeakTests
 
                 // Do a layout and make sure that TextBox gets added to visual tree and its 
                 // template applied.
-                LayoutManager.Instance.ExecuteInitialLayoutPass(window);
+                window.LayoutManager.ExecuteInitialLayoutPass(window);
                 Assert.Same(textBox, window.Presenter.Child);
 
                 // Get the border from the TextBox template.
@@ -247,7 +247,7 @@ namespace Avalonia.LeakTests
 
                 // Clear the content and ensure the TextBox is removed.
                 window.Content = null;
-                LayoutManager.Instance.ExecuteLayoutPass();
+                window.LayoutManager.ExecuteLayoutPass();
                 Assert.Null(window.Presenter.Child);
 
                 // Check that the TextBox has no subscriptions to its Classes collection.
@@ -289,12 +289,12 @@ namespace Avalonia.LeakTests
                     window.Show();
 
                     // Do a layout and make sure that TreeViewItems get realized.
-                    LayoutManager.Instance.ExecuteInitialLayoutPass(window);
+                    window.LayoutManager.ExecuteInitialLayoutPass(window);
                     Assert.Single(target.ItemContainerGenerator.Containers);
 
                     // Clear the content and ensure the TreeView is removed.
                     window.Content = null;
-                    LayoutManager.Instance.ExecuteLayoutPass();
+                    window.LayoutManager.ExecuteLayoutPass();
                     Assert.Null(window.Presenter.Child);
 
                     return window;

+ 2 - 2
tests/Avalonia.UnitTests/TestRoot.cs

@@ -43,9 +43,9 @@ namespace Avalonia.UnitTests
 
         public double LayoutScaling => 1;
 
-        public double RenderScaling => 1;
+        public ILayoutManager LayoutManager { get; set; } = new LayoutManager();
 
-        public ILayoutManager LayoutManager => AvaloniaLocator.Current.GetService<ILayoutManager>();
+        public double RenderScaling => 1;
 
         public IRenderer Renderer { get; set; }
 

+ 1 - 10
tests/Avalonia.UnitTests/TestServices.cs

@@ -23,7 +23,6 @@ namespace Avalonia.UnitTests
     {
         public static readonly TestServices StyledWindow = new TestServices(
             assetLoader: new AssetLoader(),
-            layoutManager: new LayoutManager(),
             platform: new AppBuilder().RuntimePlatform,
             renderInterface: new MockPlatformRenderInterface(),
             standardCursorFactory: Mock.Of<IStandardCursorFactory>(),
@@ -52,10 +51,7 @@ namespace Avalonia.UnitTests
             keyboardDevice: () => new KeyboardDevice(),
             keyboardNavigation: new KeyboardNavigationHandler(),
             inputManager: new InputManager());
-
-        public static readonly TestServices RealLayoutManager = new TestServices(
-            layoutManager: new LayoutManager());
-
+        
         public static readonly TestServices RealStyler = new TestServices(
             styler: new Styler());
 
@@ -65,7 +61,6 @@ namespace Avalonia.UnitTests
             IInputManager inputManager = null,
             Func<IKeyboardDevice> keyboardDevice = null,
             IKeyboardNavigationHandler keyboardNavigation = null,
-            ILayoutManager layoutManager = null,
             Func<IMouseDevice> mouseDevice = null,
             IRuntimePlatform platform = null,
             IPlatformRenderInterface renderInterface = null,
@@ -83,7 +78,6 @@ namespace Avalonia.UnitTests
             InputManager = inputManager;
             KeyboardDevice = keyboardDevice;
             KeyboardNavigation = keyboardNavigation;
-            LayoutManager = layoutManager;
             MouseDevice = mouseDevice;
             Platform = platform;
             RenderInterface = renderInterface;
@@ -101,7 +95,6 @@ namespace Avalonia.UnitTests
         public IFocusManager FocusManager { get; }
         public Func<IKeyboardDevice> KeyboardDevice { get; }
         public IKeyboardNavigationHandler KeyboardNavigation { get; }
-        public ILayoutManager LayoutManager { get; }
         public Func<IMouseDevice> MouseDevice { get; }
         public IRuntimePlatform Platform { get; }
         public IPlatformRenderInterface RenderInterface { get; }
@@ -119,7 +112,6 @@ namespace Avalonia.UnitTests
             IInputManager inputManager = null,
             Func<IKeyboardDevice> keyboardDevice = null,
             IKeyboardNavigationHandler keyboardNavigation = null,
-            ILayoutManager layoutManager = null,
             Func<IMouseDevice> mouseDevice = null,
             IRuntimePlatform platform = null,
             IPlatformRenderInterface renderInterface = null,
@@ -138,7 +130,6 @@ namespace Avalonia.UnitTests
                 inputManager: inputManager ?? InputManager,
                 keyboardDevice: keyboardDevice ?? KeyboardDevice,
                 keyboardNavigation: keyboardNavigation ?? KeyboardNavigation,
-                layoutManager: layoutManager ?? LayoutManager,
                 mouseDevice: mouseDevice ?? MouseDevice,
                 platform: platform ?? Platform,
                 renderInterface: renderInterface ?? RenderInterface,

+ 2 - 2
tests/Avalonia.UnitTests/TestTemplatedRoot.cs

@@ -39,9 +39,9 @@ namespace Avalonia.UnitTests
 
         public double LayoutScaling => 1;
 
-        public double RenderScaling => 1;
+        public ILayoutManager LayoutManager { get; set; } = new LayoutManager();
 
-        public ILayoutManager LayoutManager => AvaloniaLocator.Current.GetService<ILayoutManager>();
+        public double RenderScaling => 1;
 
         public IRenderTarget RenderTarget => null;
 

+ 0 - 1
tests/Avalonia.UnitTests/UnitTestApplication.cs

@@ -50,7 +50,6 @@ namespace Avalonia.UnitTests
                 .Bind<IInputManager>().ToConstant(Services.InputManager)
                 .Bind<IKeyboardDevice>().ToConstant(Services.KeyboardDevice?.Invoke())
                 .Bind<IKeyboardNavigationHandler>().ToConstant(Services.KeyboardNavigation)
-                .Bind<ILayoutManager>().ToConstant(Services.LayoutManager)
                 .Bind<IMouseDevice>().ToConstant(Services.MouseDevice?.Invoke())
                 .Bind<IRuntimePlatform>().ToConstant(Services.Platform)
                 .Bind<IPlatformRenderInterface>().ToConstant(Services.RenderInterface)

+ 11 - 18
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs

@@ -522,7 +522,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Should_Update_ClipBounds_For_Negative_Margin()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 Decorator decorator;
                 Border border;
@@ -542,7 +542,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
                     }
                 };
 
-                var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
+                var layout = tree.LayoutManager;
                 layout.ExecuteInitialLayoutPass(tree);
 
                 var scene = new Scene(tree);
@@ -566,7 +566,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Should_Update_Descendent_Tranform_When_Margin_Changed()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 Decorator decorator;
                 Border border;
@@ -585,7 +585,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
                     }
                 };
 
-                var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
+                var layout = tree.LayoutManager;
                 layout.ExecuteInitialLayoutPass(tree);
 
                 var scene = new Scene(tree);
@@ -613,7 +613,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void DirtyRects_Should_Contain_Old_And_New_Bounds_When_Margin_Changed()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 Decorator decorator;
                 Border border;
@@ -633,7 +633,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
                     }
                 };
 
-                var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
+                var layout = tree.LayoutManager;
                 layout.ExecuteInitialLayoutPass(tree);
 
                 var scene = new Scene(tree);
@@ -660,7 +660,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Resizing_Scene_Should_Add_DirtyRects()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 Decorator decorator;
                 Border border;
@@ -707,7 +707,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Setting_Opacity_Should_Add_Descendent_Bounds_To_DirtyRects()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 Decorator decorator;
                 Border border;
@@ -744,7 +744,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Should_Set_GeometryClip()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 var clip = StreamGeometry.Parse("M100,0 L0,100 100,100");
                 Decorator decorator;
@@ -768,7 +768,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Disposing_Scene_Releases_DrawOperation_References()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 var bitmap = RefCountable.Create(Mock.Of<IBitmapImpl>());
                 Image img;
@@ -800,7 +800,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Replacing_Control_Releases_DrawOperation_Reference()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 var bitmap = RefCountable.Create(Mock.Of<IBitmapImpl>());
                 Image img;
@@ -830,12 +830,5 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
                 }
             }
         }
-
-        private IDisposable TestApplication()
-        {
-            return UnitTestApplication.Start(
-                TestServices.MockPlatformRenderInterface.With(
-                    layoutManager: new LayoutManager()));
-        }
     }
 }

+ 10 - 10
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs

@@ -17,7 +17,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Control_With_Animated_Opacity_And_Children_Should_Start_New_Layer()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 Decorator decorator;
                 Border border;
@@ -39,7 +39,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
                     }
                 };
 
-                var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
+                var layout = tree.LayoutManager;
                 layout.ExecuteInitialLayoutPass(tree);
 
                 var animation = new BehaviorSubject<double>(0.5);
@@ -85,7 +85,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Control_With_Animated_Opacity_And_No_Children_Should_Not_Start_New_Layer()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 Decorator decorator;
                 Border border;
@@ -104,7 +104,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
                     }
                 };
 
-                var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
+                var layout = tree.LayoutManager;
                 layout.ExecuteInitialLayoutPass(tree);
 
                 var animation = new BehaviorSubject<double>(0.5);
@@ -121,7 +121,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Removing_Control_With_Animated_Opacity_Should_Remove_Layers()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 Decorator decorator;
                 Border border;
@@ -146,7 +146,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
                     }
                 };
 
-                var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
+                var layout = tree.LayoutManager;
                 layout.ExecuteInitialLayoutPass(tree);
 
                 var animation = new BehaviorSubject<double>(0.5);
@@ -171,7 +171,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void Hiding_Transparent_Control_Should_Remove_Layers()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 Decorator decorator;
                 Border border;
@@ -196,7 +196,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
                     }
                 };
 
-                var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
+                var layout = tree.LayoutManager;
                 layout.ExecuteInitialLayoutPass(tree);
 
                 var animation = new BehaviorSubject<double>(0.5);
@@ -221,7 +221,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         [Fact]
         public void GeometryClip_Should_Affect_Child_Layers()
         {
-            using (TestApplication())
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 var clip = StreamGeometry.Parse("M100,0 L0,100 100,100");
                 Decorator decorator;
@@ -240,7 +240,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
                     }
                 };
 
-                var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
+                var layout = tree.LayoutManager;
                 layout.ExecuteInitialLayoutPass(tree);
 
                 var animation = new BehaviorSubject<double>(0.5);