Przeglądaj źródła

Remove IStyler and make style apply internal.

- Removes the `IStyler` service and the `Styler` implementation
- Moves the logic for applying styles and control themes into `StyledElement`
- Removes the style `TryAttach` method from the public API
- Removes style caching for now - this will need to be added back
Steven Kirk 2 lat temu
rodzic
commit
1a338ac087
30 zmienionych plików z 494 dodań i 636 usunięć
  1. 85 38
      src/Avalonia.Base/StyledElement.cs
  2. 10 17
      src/Avalonia.Base/Styling/ControlTheme.cs
  3. 0 10
      src/Avalonia.Base/Styling/IStyle.cs
  4. 0 5
      src/Avalonia.Base/Styling/IStyleable.cs
  5. 0 8
      src/Avalonia.Base/Styling/IStyler.cs
  6. 24 30
      src/Avalonia.Base/Styling/Style.cs
  7. 17 13
      src/Avalonia.Base/Styling/StyleBase.cs
  8. 0 58
      src/Avalonia.Base/Styling/StyleCache.cs
  9. 0 35
      src/Avalonia.Base/Styling/Styler.cs
  10. 22 25
      src/Avalonia.Base/Styling/Styles.cs
  11. 0 2
      src/Avalonia.Controls/Application.cs
  12. 1 2
      src/Avalonia.Controls/TopLevel.cs
  13. 0 2
      src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs
  14. 1 1
      tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs
  15. 84 110
      tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs
  16. 40 38
      tests/Avalonia.Base.UnitTests/Styling/StyledElementTests.cs
  17. 4 17
      tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs
  18. 0 1
      tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs
  19. 0 1
      tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs
  20. 33 30
      tests/Avalonia.Controls.UnitTests/ContentControlTests.cs
  21. 2 2
      tests/Avalonia.Controls.UnitTests/ListBoxTests.cs
  22. 12 0
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
  23. 121 128
      tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs
  24. 12 16
      tests/Avalonia.Controls.UnitTests/TabControlTests.cs
  25. 1 1
      tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
  26. 11 14
      tests/Avalonia.Controls.UnitTests/UserControlTests.cs
  27. 5 16
      tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs
  28. 6 0
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
  29. 1 13
      tests/Avalonia.UnitTests/TestServices.cs
  30. 2 3
      tests/Avalonia.UnitTests/UnitTestApplication.cs

+ 85 - 38
src/Avalonia.Base/StyledElement.cs

@@ -355,22 +355,19 @@ namespace Avalonia
         {
             if (_initCount == 0 && !_styled)
             {
-                var styler = AvaloniaLocator.Current.GetService<IStyler>();
                 var hasPromotedTheme = _hasPromotedTheme;
 
-                if (styler is object)
-                {
-                    GetValueStore().BeginStyling();
+                GetValueStore().BeginStyling();
 
-                    try
-                    {
-                        styler.ApplyStyles(this);
-                    }
-                    finally
-                    {
-                        _styled = true;
-                        GetValueStore().EndStyling();
-                    }
+                try
+                {
+                    ApplyControlTheme();
+                    ApplyStyles(this);
+                }
+                finally
+                {
+                    _styled = true;
+                    GetValueStore().EndStyling();
                 }
 
                 if (hasPromotedTheme)
@@ -509,31 +506,6 @@ namespace Avalonia
             };
         }
 
-        ControlTheme? IStyleable.GetEffectiveTheme()
-        {
-            var theme = Theme;
-
-            // Explitly set Theme property takes precedence.
-            if (theme is not null)
-                return theme;
-
-            // If the Theme property is not set, try to find a ControlTheme resource with our StyleKey.
-            if (_implicitTheme is null)
-            {
-                var key = ((IStyleable)this).StyleKey;
-
-                if (this.TryFindResource(key, out var value) && value is ControlTheme t)
-                    _implicitTheme = t;
-                else
-                    _implicitTheme = s_invalidTheme;
-            }
-
-            if (_implicitTheme != s_invalidTheme)
-                return _implicitTheme;
-
-            return null;
-        }
-
         void IStyleable.DetachStyles() => DetachStyles();
 
         void IStyleHost.StylesAdded(IReadOnlyList<IStyle> styles)
@@ -670,6 +642,31 @@ namespace Avalonia
         {
         }
 
+        internal ControlTheme? GetEffectiveTheme()
+        {
+            var theme = Theme;
+
+            // Explitly set Theme property takes precedence.
+            if (theme is not null)
+                return theme;
+
+            // If the Theme property is not set, try to find a ControlTheme resource with our StyleKey.
+            if (_implicitTheme is null)
+            {
+                var key = ((IStyleable)this).StyleKey;
+
+                if (this.TryFindResource(key, out var value) && value is ControlTheme t)
+                    _implicitTheme = t;
+                else
+                    _implicitTheme = s_invalidTheme;
+            }
+
+            if (_implicitTheme != s_invalidTheme)
+                return _implicitTheme;
+
+            return null;
+        }
+
         private static void DataContextNotifying(IAvaloniaObject o, bool updateStarted)
         {
             if (o is StyledElement element)
@@ -734,6 +731,56 @@ namespace Avalonia
             }
         }
 
+        private void ApplyControlTheme()
+        {
+            var theme = GetEffectiveTheme();
+
+            if (theme is not null)
+                ApplyControlTheme(theme);
+
+            if (TemplatedParent is StyledElement styleableParent &&
+                styleableParent.GetEffectiveTheme() is { } parentTheme)
+            {
+                ApplyControlTheme(parentTheme);
+            }
+        }
+
+        private void ApplyControlTheme(ControlTheme theme)
+        {
+            if (theme.BasedOn is ControlTheme basedOn)
+                ApplyControlTheme(basedOn);
+
+            theme.TryAttach(this, null);
+
+            if (theme.HasChildren)
+            {
+                foreach (var child in theme.Children)
+                    ApplyStyle(child, null);
+            }
+        }
+
+        private void ApplyStyles(IStyleHost host)
+        {
+            var parent = host.StylingParent;
+            if (parent != null)
+                ApplyStyles(parent);
+            
+            if (host.IsStylesInitialized)
+            {
+                foreach (var style in host.Styles)
+                    ApplyStyle(style, host);
+            }
+        }
+
+        private void ApplyStyle(IStyle style, IStyleHost? host)
+        {
+            if (style is Style s)
+                s.TryAttach(this, host);
+
+            foreach (var child in style.Children)
+                ApplyStyle(child, host);
+        }
+
         private void OnAttachedToLogicalTreeCore(LogicalTreeAttachmentEventArgs e)
         {
             if (this.GetLogicalParent() == null && !(this is ILogicalRoot))

+ 10 - 17
src/Avalonia.Base/Styling/ControlTheme.cs

@@ -29,34 +29,27 @@ namespace Avalonia.Styling
         /// </summary>
         public ControlTheme? BasedOn { get; set; }
 
-        public override SelectorMatchResult TryAttach(IStyleable target, object? host)
+        public override string ToString() => TargetType?.Name ?? "ControlTheme";
+
+        internal override void SetParent(StyleBase? parent)
+        {
+            throw new InvalidOperationException("ControlThemes cannot be added as a nested style.");
+        }
+
+        internal override SelectorMatchResult TryAttach(IStyleable target, object? host)
         {
             _ = target ?? throw new ArgumentNullException(nameof(target));
 
             if (TargetType is null)
                 throw new InvalidOperationException("ControlTheme has no TargetType.");
 
-            var result = BasedOn?.TryAttach(target, host) ?? SelectorMatchResult.NeverThisType;
-
             if (HasSettersOrAnimations && TargetType.IsAssignableFrom(target.StyleKey))
             {
                 Attach(target, null);
-                result = SelectorMatchResult.AlwaysThisType;
+                return SelectorMatchResult.AlwaysThisType;
             }
 
-            var childResult = TryAttachChildren(target, host);
-
-            if (childResult > result)
-                result = childResult;
-
-            return result;
-        }
-
-        public override string ToString() => TargetType?.Name ?? "ControlTheme";
-
-        internal override void SetParent(StyleBase? parent)
-        {
-            throw new InvalidOperationException("ControlThemes cannot be added as a nested style.");
+            return SelectorMatchResult.NeverThisType;
         }
     }
 }

+ 0 - 10
src/Avalonia.Base/Styling/IStyle.cs

@@ -14,15 +14,5 @@ namespace Avalonia.Styling
         /// Gets a collection of child styles.
         /// </summary>
         IReadOnlyList<IStyle> Children { get; }
-
-        /// <summary>
-        /// Attaches the style and any child styles to a control if the style's selector matches.
-        /// </summary>
-        /// <param name="target">The control to attach to.</param>
-        /// <param name="host">The element that hosts the style.</param>
-        /// <returns>
-        /// A <see cref="SelectorMatchResult"/> describing how the style matches the control.
-        /// </returns>
-        SelectorMatchResult TryAttach(IStyleable target, object? host);
     }
 }

+ 0 - 5
src/Avalonia.Base/Styling/IStyleable.cs

@@ -25,11 +25,6 @@ namespace Avalonia.Styling
         /// </summary>
         ITemplatedControl? TemplatedParent { get; }
 
-        /// <summary>
-        /// Gets the effective theme for the control as used by the syling system.
-        /// </summary>
-        ControlTheme? GetEffectiveTheme();
-
         void DetachStyles();
     }
 }

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

@@ -1,8 +0,0 @@
-
-namespace Avalonia.Styling
-{
-    public interface IStyler
-    {
-        void ApplyStyles(IStyleable control);
-    }
-}

+ 24 - 30
src/Avalonia.Base/Styling/Style.cs

@@ -1,5 +1,4 @@
 using System;
-using Avalonia.PropertyStore;
 
 namespace Avalonia.Styling
 {
@@ -35,35 +34,6 @@ namespace Avalonia.Styling
             set => _selector = ValidateSelector(value);
         }
 
-        public override SelectorMatchResult TryAttach(IStyleable target, object? host)
-        {
-            _ = target ?? throw new ArgumentNullException(nameof(target));
-
-            var result = SelectorMatchResult.NeverThisType;
-
-            if (HasSettersOrAnimations)
-            {
-                var match = Selector?.Match(target, Parent, true) ??
-                    (target == host ?
-                        SelectorMatch.AlwaysThisInstance :
-                        SelectorMatch.NeverThisInstance);
-
-                if (match.IsMatch)
-                {
-                    Attach(target, match.Activator);
-                }
-
-                result = match.Result;
-            }
-
-            var childResult = TryAttachChildren(target, host);
-
-            if (childResult > result)
-                result = childResult;
-
-            return result;
-        }
-
         /// <summary>
         /// Returns a string representation of the style.
         /// </summary>
@@ -88,6 +58,30 @@ namespace Avalonia.Styling
             base.SetParent(parent);
         }
 
+        internal override SelectorMatchResult TryAttach(IStyleable target, object? host)
+        {
+            _ = target ?? throw new ArgumentNullException(nameof(target));
+
+            var result = SelectorMatchResult.NeverThisType;
+
+            if (HasSettersOrAnimations)
+            {
+                var match = Selector?.Match(target, Parent, true) ??
+                    (target == host ?
+                        SelectorMatch.AlwaysThisInstance :
+                        SelectorMatch.NeverThisInstance);
+
+                if (match.IsMatch)
+                {
+                    Attach(target, match.Activator);
+                }
+
+                result = match.Result;
+            }
+
+            return result;
+        }
+
         private static Selector? ValidateSelector(Selector? selector)
         {
             if (selector is TemplateSelector)

+ 17 - 13
src/Avalonia.Base/Styling/StyleBase.cs

@@ -18,7 +18,6 @@ namespace Avalonia.Styling
         private IResourceDictionary? _resources;
         private List<ISetter>? _setters;
         private List<IAnimation>? _animations;
-        private StyleCache? _childCache;
         private StyleInstance? _sharedInstance;
 
         public IList<IStyle> Children => _children ??= new(this);
@@ -67,6 +66,7 @@ namespace Avalonia.Styling
         bool IResourceNode.HasResources => _resources?.Count > 0;
         IReadOnlyList<IStyle> IStyle.Children => (IReadOnlyList<IStyle>?)_children ?? Array.Empty<IStyle>();
 
+        internal bool HasChildren => _children?.Count > 0;
         internal bool HasSettersOrAnimations => _setters?.Count > 0 || _animations?.Count > 0;
 
         public void Add(ISetter setter) => Setters.Add(setter);
@@ -74,14 +74,26 @@ namespace Avalonia.Styling
 
         public event EventHandler? OwnerChanged;
 
-        public abstract SelectorMatchResult TryAttach(IStyleable target, object? host);
-
         public bool TryGetResource(object key, out object? result)
         {
-            result = null;
-            return _resources?.TryGetResource(key, out result) ?? false;
+            if (_resources is not null && _resources.TryGetResource(key, out result))
+                return true;
+
+            if (_children is not null)
+            {
+                for (var i = 0; i < _children.Count; ++i)
+                {
+                    if (_children[i].TryGetResource(key, out result))
+                        return true;
+                }
+            }
+
+            result= null;
+            return false;
         }
 
+        internal abstract SelectorMatchResult TryAttach(IStyleable target, object? host);
+
         internal ValueFrame Attach(IStyleable target, IStyleActivator? activator)
         {
             if (target is not AvaloniaObject ao)
@@ -124,14 +136,6 @@ namespace Avalonia.Styling
             return instance;
         }
 
-        internal SelectorMatchResult TryAttachChildren(IStyleable target, object? host)
-        {
-            if (_children is null || _children.Count == 0)
-                return SelectorMatchResult.NeverThisType;
-            _childCache ??= new StyleCache();
-            return _childCache.TryAttach(_children, target, host);
-        }
-
         internal virtual void SetParent(StyleBase? parent) => Parent = parent;
 
         void IResourceProvider.AddOwner(IResourceHost owner)

+ 0 - 58
src/Avalonia.Base/Styling/StyleCache.cs

@@ -1,58 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Avalonia.Styling
-{
-    /// <summary>
-    /// Simple cache for improving performance of applying styles.
-    /// </summary>
-    /// <remarks>
-    /// Maps <see cref="IStyleable.StyleKey"/> to a list of styles that are known be be possible
-    /// matches.
-    /// </remarks>
-    internal class StyleCache : Dictionary<Type, List<IStyle>?>
-    {
-        public SelectorMatchResult TryAttach(IList<IStyle> styles, IStyleable target, object? host)
-        {
-            if (TryGetValue(target.StyleKey, out var cached))
-            {
-                if (cached is object)
-                {
-                    var result = SelectorMatchResult.NeverThisType;
-
-                    foreach (var style in cached)
-                    {
-                        var childResult = style.TryAttach(target, host);
-                        if (childResult > result)
-                            result = childResult;
-                    }
-
-                    return result;
-                }
-                else
-                {
-                    return SelectorMatchResult.NeverThisType;
-                }
-            }
-            else
-            {
-                List<IStyle>? matches = null;
-
-                foreach (var child in styles)
-                {
-                    if (child.TryAttach(target, host) != SelectorMatchResult.NeverThisType)
-                    {
-                        matches ??= new List<IStyle>();
-                        matches.Add(child);
-                    }
-                }
-
-                Add(target.StyleKey, matches);
-
-                return matches is null ?
-                    SelectorMatchResult.NeverThisType :
-                    SelectorMatchResult.AlwaysThisType;
-            }
-        }
-    }
-}

+ 0 - 35
src/Avalonia.Base/Styling/Styler.cs

@@ -1,35 +0,0 @@
-using System;
-
-namespace Avalonia.Styling
-{
-    public class Styler : IStyler
-    {
-        public void ApplyStyles(IStyleable target)
-        {
-            _ = target ?? throw new ArgumentNullException(nameof(target));
-
-            // Apply the control theme.
-            target.GetEffectiveTheme()?.TryAttach(target, target);
-
-            // If the control has a themed templated parent then apply the styles from the
-            // templated parent theme.
-            if (target.TemplatedParent is IStyleable styleableParent)
-                styleableParent.GetEffectiveTheme()?.TryAttach(target, styleableParent);
-
-            // Apply styles from the rest of the tree.
-            if (target is IStyleHost styleHost)
-                ApplyStyles(target, styleHost);
-        }
-
-        private void ApplyStyles(IStyleable target, IStyleHost host)
-        {
-            var parent = host.StylingParent;
-
-            if (parent != null)
-                ApplyStyles(target, parent);
-
-            if (host.IsStylesInitialized)
-                host.Styles.TryAttach(target, host);
-        }
-    }
-}

+ 22 - 25
src/Avalonia.Base/Styling/Styles.cs

@@ -5,8 +5,6 @@ using System.Collections.Specialized;
 using Avalonia.Collections;
 using Avalonia.Controls;
 
-#nullable enable
-
 namespace Avalonia.Styling
 {
     /// <summary>
@@ -20,7 +18,6 @@ namespace Avalonia.Styling
         private readonly AvaloniaList<IStyle> _styles = new();
         private IResourceHost? _owner;
         private IResourceDictionary? _resources;
-        private StyleCache? _cache;
 
         public Styles()
         {
@@ -116,12 +113,6 @@ namespace Avalonia.Styling
             set => _styles[index] = value;
         }
 
-        public SelectorMatchResult TryAttach(IStyleable target, object? host)
-        {
-            _cache ??= new StyleCache();
-            return _cache.TryAttach(this, target, host);
-        }
-
         /// <inheritdoc/>
         public bool TryGetResource(object key, out object? value)
         {
@@ -234,6 +225,22 @@ namespace Avalonia.Styling
             }
         }
 
+        internal SelectorMatchResult TryAttach(IStyleable target, object? host)
+        {
+            var result = SelectorMatchResult.NeverThisType;
+
+            foreach (var s in this)
+            {
+                if (s is not Style style)
+                    continue;
+                var r = style.TryAttach(target, host);
+                if (r > result)
+                    result = r;
+            }
+
+            return result;
+        }
+
         private static IReadOnlyList<T> ToReadOnlyList<T>(ICollection list)
         {
             if (list is IReadOnlyList<T> readOnlyList)
@@ -246,7 +253,7 @@ namespace Avalonia.Styling
             return result;
         }
 
-        private static void InternalAdd(IList items, IResourceHost? owner, ref StyleCache? cache)
+        private static void InternalAdd(IList items, IResourceHost? owner)
         {
             if (owner is not null)
             {
@@ -260,14 +267,9 @@ namespace Avalonia.Styling
 
                 (owner as IStyleHost)?.StylesAdded(ToReadOnlyList<IStyle>(items));
             }
-
-            if (items.Count > 0)
-            {
-                cache = null;
-            }
         }
 
-        private static void InternalRemove(IList items, IResourceHost? owner, ref StyleCache? cache)
+        private static void InternalRemove(IList items, IResourceHost? owner)
         {
             if (owner is not null)
             {
@@ -281,11 +283,6 @@ namespace Avalonia.Styling
 
                 (owner as IStyleHost)?.StylesRemoved(ToReadOnlyList<IStyle>(items));
             }
-
-            if (items.Count > 0)
-            {
-                cache = null;
-            }
         }
 
         private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
@@ -300,14 +297,14 @@ namespace Avalonia.Styling
             switch (e.Action)
             {
                 case NotifyCollectionChangedAction.Add:
-                    InternalAdd(e.NewItems!, currentOwner, ref _cache);
+                    InternalAdd(e.NewItems!, currentOwner);
                     break;
                 case NotifyCollectionChangedAction.Remove:
-                    InternalRemove(e.OldItems!, currentOwner, ref _cache);
+                    InternalRemove(e.OldItems!, currentOwner);
                     break;
                 case NotifyCollectionChangedAction.Replace:
-                    InternalRemove(e.OldItems!, currentOwner, ref _cache);
-                    InternalAdd(e.NewItems!, currentOwner, ref _cache);
+                    InternalRemove(e.OldItems!, currentOwner);
+                    InternalAdd(e.NewItems!, currentOwner);
                     break;
             }
 

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

@@ -39,7 +39,6 @@ namespace Avalonia
 
         private readonly Lazy<IClipboard?> _clipboard =
             new Lazy<IClipboard?>(() => (IClipboard?)AvaloniaLocator.Current.GetService(typeof(IClipboard)));
-        private readonly Styler _styler = new Styler();
         private Styles? _styles;
         private IResourceDictionary? _resources;
         private bool _notifyingResourcesChanged;
@@ -232,7 +231,6 @@ namespace Avalonia
                 .Bind<IFocusManager>().ToConstant(FocusManager)
                 .Bind<IInputManager>().ToConstant(InputManager)
                 .Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>()
-                .Bind<IStyler>().ToConstant(_styler)
                 .Bind<IScheduler>().ToConstant(AvaloniaScheduler.Instance)
                 .Bind<IDragDropDevice>().ToConstant(DragDropDevice.Instance);
             

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

@@ -145,7 +145,6 @@ namespace Avalonia.Controls
             _actualTransparencyLevel = PlatformImpl.TransparencyLevel;            
 
             dependencyResolver = dependencyResolver ?? AvaloniaLocator.Current;
-            var styler = TryGetService<IStyler>(dependencyResolver);
 
             _accessKeyHandler = TryGetService<IAccessKeyHandler>(dependencyResolver);
             _inputManager = TryGetService<IInputManager>(dependencyResolver);
@@ -183,7 +182,7 @@ namespace Avalonia.Controls
                 _globalStyles.GlobalStylesRemoved += ((IStyleHost)this).StylesRemoved;
             }
 
-            styler?.ApplyStyles(this);
+            ApplyStyling();
 
             ClientSize = impl.ClientSize;
             FrameSize = impl.FrameSize;

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

@@ -82,8 +82,6 @@ namespace Avalonia.Markup.Xaml.Styling
             }
         }
 
-        public SelectorMatchResult TryAttach(IStyleable target, object? host) => Loaded.TryAttach(target, host);
-
         public bool TryGetResource(object key, out object? value)
         {
             if (!_isLoading)

+ 1 - 1
tests/Avalonia.Base.UnitTests/Animation/AnimatableTests.cs

@@ -498,7 +498,7 @@ namespace Avalonia.Base.UnitTests.Animation
         private static IDisposable Start()
         {
             var clock = new MockGlobalClock();
-            var services = TestServices.RealStyler.With(globalClock: clock);
+            var services = new TestServices(globalClock: clock);
             return UnitTestApplication.Start(services);
         }
 

+ 84 - 110
tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs

@@ -5,7 +5,6 @@ using Avalonia.Base.UnitTests.Animation;
 using Avalonia.Controls;
 using Avalonia.Controls.Templates;
 using Avalonia.Data;
-using Avalonia.Diagnostics;
 using Avalonia.Styling;
 using Avalonia.UnitTests;
 using Moq;
@@ -301,8 +300,6 @@ namespace Avalonia.Base.UnitTests.Styling
         [Fact]
         public void Inactive_Values_Should_Not_Be_Made_Active_During_Style_Attach()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
-
             var root = new TestRoot
             {
                 Styles =
@@ -337,8 +334,6 @@ namespace Avalonia.Base.UnitTests.Styling
         [Fact]
         public void Inactive_Bindings_Should_Not_Be_Made_Active_During_Style_Attach()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
-
             var root = new TestRoot
             {
                 Styles =
@@ -380,8 +375,6 @@ namespace Avalonia.Base.UnitTests.Styling
         [Fact]
         public void Inactive_Values_Should_Not_Be_Made_Active_During_Style_Detach()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
-
             var root = new TestRoot
             {
                 Styles =
@@ -417,8 +410,6 @@ namespace Avalonia.Base.UnitTests.Styling
         [Fact]
         public void Inactive_Values_Should_Not_Be_Made_Active_During_Style_Detach_2()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
-
             var root = new TestRoot
             {
                 Styles =
@@ -454,8 +445,6 @@ namespace Avalonia.Base.UnitTests.Styling
         [Fact]
         public void Inactive_Bindings_Should_Not_Be_Made_Active_During_Style_Detach()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
-
             var root = new TestRoot
             {
                 Styles =
@@ -598,41 +587,36 @@ namespace Avalonia.Base.UnitTests.Styling
         [Fact]
         public void Removing_Style_Should_Detach_From_Control()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            var border = new Border();
+            var root = new TestRoot
             {
-                var border = new Border();
-                var root = new TestRoot
-                {
-                    Styles =
-                    { 
-                        new Style(x => x.OfType<Border>())
+                Styles =
+                { 
+                    new Style(x => x.OfType<Border>())
+                    {
+                        Setters =
                         {
-                            Setters =
-                            {
-                                new Setter(Border.BorderThicknessProperty, new Thickness(4)),
-                            }
+                            new Setter(Border.BorderThicknessProperty, new Thickness(4)),
                         }
-                    },
-                    Child = border,
-                };
+                    }
+                },
+                Child = border,
+            };
 
-                root.Measure(Size.Infinity);
-                Assert.Equal(new Thickness(4), border.BorderThickness);
+            root.Measure(Size.Infinity);
+            Assert.Equal(new Thickness(4), border.BorderThickness);
 
-                root.Styles.RemoveAt(0);
-                Assert.Equal(new Thickness(0), border.BorderThickness);
-            }
+            root.Styles.RemoveAt(0);
+            Assert.Equal(new Thickness(0), border.BorderThickness);
         }
 
         [Fact]
         public void Adding_Style_Should_Attach_To_Control()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            var border = new Border();
+            var root = new TestRoot
             {
-                var border = new Border();
-                var root = new TestRoot
-                {
-                    Styles =
+                Styles =
                     {
                         new Style(x => x.OfType<Border>())
                         {
@@ -642,34 +626,31 @@ namespace Avalonia.Base.UnitTests.Styling
                             }
                         }
                     },
-                    Child = border,
-                };
+                Child = border,
+            };
 
-                root.Measure(Size.Infinity);
-                Assert.Equal(new Thickness(4), border.BorderThickness);
+            root.Measure(Size.Infinity);
+            Assert.Equal(new Thickness(4), border.BorderThickness);
 
-                root.Styles.Add(new Style(x => x.OfType<Border>())
-                {
-                    Setters =
+            root.Styles.Add(new Style(x => x.OfType<Border>())
+            {
+                Setters =
                     {
                         new Setter(Border.BorderThicknessProperty, new Thickness(6)),
                     }
-                });
+            });
 
-                root.Measure(Size.Infinity);
-                Assert.Equal(new Thickness(6), border.BorderThickness);
-            }
+            root.Measure(Size.Infinity);
+            Assert.Equal(new Thickness(6), border.BorderThickness);
         }
 
         [Fact]
         public void Removing_Style_With_Nested_Style_Should_Detach_From_Control()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            var border = new Border();
+            var root = new TestRoot
             {
-                var border = new Border();
-                var root = new TestRoot
-                {
-                    Styles =
+                Styles =
                     {
                         new Styles
                         {
@@ -682,96 +663,89 @@ namespace Avalonia.Base.UnitTests.Styling
                             }
                         }
                     },
-                    Child = border,
-                };
+                Child = border,
+            };
 
-                root.Measure(Size.Infinity);
-                Assert.Equal(new Thickness(4), border.BorderThickness);
+            root.Measure(Size.Infinity);
+            Assert.Equal(new Thickness(4), border.BorderThickness);
 
-                root.Styles.RemoveAt(0);
-                Assert.Equal(new Thickness(0), border.BorderThickness);
-            }
+            root.Styles.RemoveAt(0);
+            Assert.Equal(new Thickness(0), border.BorderThickness);
         }
-        
+
         [Fact]
         public void Adding_Nested_Style_Should_Attach_To_Control()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            var border = new Border();
+            var root = new TestRoot
             {
-                var border = new Border();
-                var root = new TestRoot
+                Styles =
                 {
-                    Styles =
+                    new Styles
                     {
-                        new Styles
+                        new Style(x => x.OfType<Border>())
                         {
-                            new Style(x => x.OfType<Border>())
+                            Setters =
                             {
-                                Setters =
-                                {
-                                    new Setter(Border.BorderThicknessProperty, new Thickness(4)),
-                                }
+                                new Setter(Border.BorderThicknessProperty, new Thickness(4)),
                             }
                         }
-                    },
-                    Child = border,
-                };
+                    }
+                },
+                Child = border,
+            };
 
-                root.Measure(Size.Infinity);
-                Assert.Equal(new Thickness(4), border.BorderThickness);
+            root.Measure(Size.Infinity);
+            Assert.Equal(new Thickness(4), border.BorderThickness);
 
-                ((Styles)root.Styles[0]).Add(new Style(x => x.OfType<Border>())
+            ((Styles)root.Styles[0]).Add(new Style(x => x.OfType<Border>())
+            {
+                Setters =
                 {
-                    Setters =
-                    {
-                        new Setter(Border.BorderThicknessProperty, new Thickness(6)),
-                    }
-                });
+                    new Setter(Border.BorderThicknessProperty, new Thickness(6)),
+                }
+            });
 
-                root.Measure(Size.Infinity);
-                Assert.Equal(new Thickness(6), border.BorderThickness);
-            }
+            root.Measure(Size.Infinity);
+            Assert.Equal(new Thickness(6), border.BorderThickness);
         }
 
         [Fact]
         public void Removing_Nested_Style_Should_Detach_From_Control()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            var border = new Border();
+            var root = new TestRoot
             {
-                var border = new Border();
-                var root = new TestRoot
+                Styles =
                 {
-                    Styles =
+                    new Styles
                     {
-                        new Styles
+                        new Style(x => x.OfType<Border>())
                         {
-                            new Style(x => x.OfType<Border>())
+                            Setters =
                             {
-                                Setters =
-                                {
-                                    new Setter(Border.BorderThicknessProperty, new Thickness(4)),
-                                }
-                            },
-                            new Style(x => x.OfType<Border>())
+                                new Setter(Border.BorderThicknessProperty, new Thickness(4)),
+                            }
+                        },
+                        new Style(x => x.OfType<Border>())
+                        {
+                            Setters =
                             {
-                                Setters =
-                                {
-                                    new Setter(Border.BorderThicknessProperty, new Thickness(6)),
-                                }
-                            },
-                        }
-                    },
-                    Child = border,
-                };
+                                new Setter(Border.BorderThicknessProperty, new Thickness(6)),
+                            }
+                        },
+                    }
+                },
+                Child = border,
+            };
 
-                root.Measure(Size.Infinity);
-                Assert.Equal(new Thickness(6), border.BorderThickness);
+            root.Measure(Size.Infinity);
+            Assert.Equal(new Thickness(6), border.BorderThickness);
 
-                ((Styles)root.Styles[0]).RemoveAt(1);
+            ((Styles)root.Styles[0]).RemoveAt(1);
 
-                root.Measure(Size.Infinity);
-                Assert.Equal(new Thickness(4), border.BorderThickness);
-            }
+            root.Measure(Size.Infinity);
+            Assert.Equal(new Thickness(4), border.BorderThickness);
         }
 
         [Fact]

+ 40 - 38
tests/Avalonia.Base.UnitTests/Styling/StyledElementTests.cs

@@ -249,65 +249,67 @@ namespace Avalonia.Base.UnitTests.Styling
         }
 
         [Fact]
-        public void Adding_Tree_To_IStyleRoot_Should_Style_Controls()
+        public void Adding_Tree_To_Root_Should_Style_Controls()
         {
-            using (AvaloniaLocator.EnterScope())
+            var root = new TestRoot
             {
-                var root = new TestRoot();
-                var parent = new Border();
-                var child = new Border();
-                var grandchild = new Control();
-                var styler = new Mock<IStyler>();
-
-                AvaloniaLocator.CurrentMutable.Bind<IStyler>().ToConstant(styler.Object);
+                Styles =
+                {
+                    new Style(x => x.Is<Control>())
+                    {
+                        Setters = { new Setter(Control.TagProperty, "foo") }
+                    }
+                }
+            };
 
-                parent.Child = child;
-                child.Child = grandchild;
+            var grandchild = new Control();
+            var child = new Border { Child = grandchild };
+            var parent = new Border { Child = child };
 
-                styler.Verify(x => x.ApplyStyles(It.IsAny<IStyleable>()), Times.Never());
+            Assert.Null(parent.Tag);
+            Assert.Null(child.Tag);
+            Assert.Null(grandchild.Tag);
 
-                root.Child = parent;
+            root.Child = parent;
 
-                styler.Verify(x => x.ApplyStyles(parent), Times.Once());
-                styler.Verify(x => x.ApplyStyles(child), Times.Once());
-                styler.Verify(x => x.ApplyStyles(grandchild), Times.Once());
-            }
+            Assert.Equal("foo", parent.Tag);
+            Assert.Equal("foo", child.Tag);
+            Assert.Equal("foo", grandchild.Tag);
         }
 
         [Fact]
         public void Styles_Not_Applied_Until_Initialization_Finished()
         {
-            using (AvaloniaLocator.EnterScope())
+            var root = new TestRoot
             {
-                var root = new TestRoot();
-                var child = new Border();
-                var styler = new Mock<IStyler>();
+                Styles =
+                {
+                    new Style(x => x.Is<Control>())
+                    {
+                        Setters = { new Setter(Control.TagProperty, "foo") }
+                    }
+                }
+            };
 
-                AvaloniaLocator.CurrentMutable.Bind<IStyler>().ToConstant(styler.Object);
+            var child = new Border();
 
-                ((ISupportInitialize)child).BeginInit();
-                root.Child = child;
-                styler.Verify(x => x.ApplyStyles(It.IsAny<IStyleable>()), Times.Never());
+            ((ISupportInitialize)child).BeginInit();
+            root.Child = child;
+            Assert.Null(child.Tag);
 
-                ((ISupportInitialize)child).EndInit();
-                styler.Verify(x => x.ApplyStyles(child), Times.Once());
-            }
+            ((ISupportInitialize)child).EndInit();
+            Assert.Equal("foo", child.Tag);
         }
 
         [Fact]
         public void Name_Cannot_Be_Set_After_Added_To_Logical_Tree()
         {
-            using (AvaloniaLocator.EnterScope())
-            {
-                var root = new TestRoot();
-                var child = new Border();
-
-                AvaloniaLocator.CurrentMutable.BindToSelf<IStyler>(new Styler());
+            var root = new TestRoot();
+            var child = new Border();
 
-                root.Child = child;
+            root.Child = child;
 
-                Assert.Throws<InvalidOperationException>(() => child.Name = "foo");
-            }
+            Assert.Throws<InvalidOperationException>(() => child.Name = "foo");
         }
 
         [Fact]
@@ -328,7 +330,7 @@ namespace Avalonia.Base.UnitTests.Styling
         [Fact]
         public void Style_Is_Removed_When_Control_Removed_From_Logical_Tree()
         {
-            var app = UnitTestApplication.Start(TestServices.RealStyler);
+            var app = UnitTestApplication.Start();
             var target = new Border();
             var root = new TestRoot
             {

+ 4 - 17
tests/Avalonia.Base.UnitTests/Styling/StyledElementTests_Theming.cs

@@ -19,7 +19,6 @@ public class StyledElementTests_Theming
         [Fact]
         public void Theme_Is_Applied_When_Attached_To_Logical_Tree()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = CreateTarget();
 
             Assert.Null(target.Template);
@@ -37,7 +36,6 @@ public class StyledElementTests_Theming
         [Fact]
         public void Theme_Is_Applied_To_Derived_Class_When_Attached_To_Logical_Tree()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = new DerivedThemedControl
             {
                 Theme = CreateTheme(),
@@ -58,7 +56,6 @@ public class StyledElementTests_Theming
         [Fact]
         public void Theme_Is_Detached_When_Theme_Property_Cleared()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = CreateTarget();
             var root = CreateRoot(target);
 
@@ -71,8 +68,6 @@ public class StyledElementTests_Theming
         [Fact]
         public void Theme_Is_Detached_From_Template_Controls_When_Theme_Property_Cleared()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
-
             var theme = new ControlTheme
             {
                 TargetType = typeof(ThemedControl),
@@ -105,7 +100,6 @@ public class StyledElementTests_Theming
         [Fact]
         public void Theme_Is_Applied_On_Layout_After_Theme_Property_Changes()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = new ThemedControl();
             var root = CreateRoot(target);
 
@@ -124,7 +118,6 @@ public class StyledElementTests_Theming
         [Fact]
         public void BasedOn_Theme_Is_Applied_When_Attached_To_Logical_Tree()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = CreateTarget(CreateDerivedTheme());
 
             Assert.Null(target.Template);
@@ -163,7 +156,6 @@ public class StyledElementTests_Theming
         [Fact]
         public void Implicit_Theme_Is_Applied_When_Attached_To_Logical_Tree()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = CreateTarget();
             var root = CreateRoot(target);
             Assert.NotNull(target.Template);
@@ -178,21 +170,19 @@ public class StyledElementTests_Theming
         [Fact]
         public void Implicit_Theme_Is_Cleared_When_Removed_From_Logical_Tree()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = CreateTarget();
             var root = CreateRoot(target);
             
-            Assert.NotNull(((IStyleable)target).GetEffectiveTheme());
+            Assert.NotNull(target.GetEffectiveTheme());
 
             root.Child = null;
 
-            Assert.Null(((IStyleable)target).GetEffectiveTheme());
+            Assert.Null(target.GetEffectiveTheme());
         }
 
         [Fact]
         public void Nested_Style_Can_Override_Property_In_Inner_Templated_Control()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = new ThemedControl2
             {
                 Theme = new ControlTheme(typeof(ThemedControl2))
@@ -236,7 +226,6 @@ public class StyledElementTests_Theming
         [Fact]
         public void Theme_Is_Applied_When_Attached_To_Logical_Tree()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = CreateTarget();
 
             Assert.Null(target.Theme);
@@ -248,16 +237,15 @@ public class StyledElementTests_Theming
             Assert.NotNull(target.Template);
 
             var border = Assert.IsType<Border>(target.VisualChild);
-            Assert.Equal(border.Background, Brushes.Red);
+            Assert.Equal(Brushes.Red, border.Background);
 
             target.Classes.Add("foo");
-            Assert.Equal(border.Background, Brushes.Green);
+            Assert.Equal(Brushes.Green, border.Background);
         }
 
         [Fact]
         public void Theme_Can_Be_Changed_By_Style_Class()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = CreateTarget();
             var theme1 = CreateTheme();
             var theme2 = new ControlTheme(typeof(ThemedControl));
@@ -290,7 +278,6 @@ public class StyledElementTests_Theming
         [Fact]
         public void Theme_Can_Be_Set_To_LocalValue_While_Updating_Due_To_Style_Class()
         {
-            using var app = UnitTestApplication.Start(TestServices.RealStyler);
             var target = CreateTarget();
             var theme1 = CreateTheme();
             var theme2 = new ControlTheme(typeof(ThemedControl));

+ 0 - 1
tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs

@@ -22,7 +22,6 @@ namespace Avalonia.Benchmarks.Styling
                 platform: new AppBuilder().RuntimePlatform,
                 renderInterface: new MockPlatformRenderInterface(),
                 standardCursorFactory: Mock.Of<ICursorFactory>(),
-                styler: new Styler(),
                 theme: () => CreateTheme(),
                 threadingInterface: new NullThreadingPlatform(),
                 fontManagerImpl: new MockFontManagerImpl(),

+ 0 - 1
tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs

@@ -46,7 +46,6 @@ namespace Avalonia.Benchmarks.Themes
                 platform: new AppBuilder().RuntimePlatform,
                 renderInterface: new MockPlatformRenderInterface(),
                 standardCursorFactory: Mock.Of<ICursorFactory>(),
-                styler: new Styler(),
                 theme: () => LoadFluentTheme(),
                 threadingInterface: new NullThreadingPlatform(),
                 fontManagerImpl: new MockFontManagerImpl(),

+ 33 - 30
tests/Avalonia.Controls.UnitTests/ContentControlTests.cs

@@ -37,11 +37,19 @@ namespace Avalonia.Controls.UnitTests
         [Fact]
         public void Templated_Children_Should_Be_Styled()
         {
-            var root = new TestRoot();
+            var root = new TestRoot
+            {
+                Styles =
+                {
+                    new Style(x => x.Is<Control>())
+                    {
+                        Setters = { new Setter(Control.TagProperty, "foo") }
+                    }
+                }
+            };
+
             var target = new ContentControl();
-            var styler = new Mock<IStyler>();
 
-            AvaloniaLocator.CurrentMutable.Bind<IStyler>().ToConstant(styler.Object);
             target.Content = "Foo";
             target.Template = GetTemplate();
             root.Child = target;
@@ -49,10 +57,8 @@ namespace Avalonia.Controls.UnitTests
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 
-            styler.Verify(x => x.ApplyStyles(It.IsAny<ContentControl>()), Times.Once());
-            styler.Verify(x => x.ApplyStyles(It.IsAny<Border>()), Times.Once());
-            styler.Verify(x => x.ApplyStyles(It.IsAny<ContentPresenter>()), Times.Once());
-            styler.Verify(x => x.ApplyStyles(It.IsAny<TextBlock>()), Times.Once());
+            foreach (Control child in target.GetTemplateChildren())
+                Assert.Equal("foo", child.Tag);
         }
 
         [Fact]
@@ -332,40 +338,37 @@ namespace Avalonia.Controls.UnitTests
         [Fact]
         public void Should_Set_Child_LogicalParent_After_Removing_And_Adding_Back_To_Logical_Tree()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            var target = new ContentControl();
+            var root = new TestRoot
             {
-                var target = new ContentControl();
-                var root = new TestRoot
+                Styles =
                 {
-                    Styles =
+                    new Style(x => x.OfType<ContentControl>())
                     {
-                        new Style(x => x.OfType<ContentControl>())
+                        Setters =
                         {
-                            Setters =
-                            {
-                                new Setter(ContentControl.TemplateProperty, GetTemplate()),
-                            }
+                            new Setter(ContentControl.TemplateProperty, GetTemplate()),
                         }
-                    },
-                    Child = target
-                };
+                    }
+                },
+                Child = target
+            };
 
-                target.Content = "Foo";
-                target.ApplyTemplate();
-                target.Presenter.ApplyTemplate();
+            target.Content = "Foo";
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
 
-                Assert.Equal(target, target.Presenter.Child.LogicalParent);
+            Assert.Equal(target, target.Presenter.Child.LogicalParent);
 
-                root.Child = null;
+            root.Child = null;
 
-                Assert.Null(target.Template);
+            Assert.Null(target.Template);
 
-                target.Content = null;
-                root.Child = target;
-                target.Content = "Bar";
+            target.Content = null;
+            root.Child = target;
+            target.Content = "Bar";
 
-                Assert.Equal(target, target.Presenter.Child.LogicalParent);
-            }
+            Assert.Equal(target, target.Presenter.Child.LogicalParent);
         }
 
         private FuncControlTemplate GetTemplate()

+ 2 - 2
tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

@@ -99,7 +99,7 @@ namespace Avalonia.Controls.UnitTests
             using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 var items = new[] { "Foo", "Bar", "Baz " };
-                var theme = new ControlTheme();
+                var theme = new ControlTheme(typeof(ListBoxItem));
                 var target = new ListBox
                 {
                     Template = ListBoxTemplate(),
@@ -121,7 +121,7 @@ namespace Avalonia.Controls.UnitTests
             using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
             {
                 var items = new[] { "Foo", "Bar", "Baz " };
-                var theme = new ControlTheme();
+                var theme = new ControlTheme(typeof(ListBoxItem));
                 var target = new ListBox
                 {
                     Template = ListBoxTemplate(),

+ 12 - 0
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@@ -998,6 +998,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
         [Fact]
         public void Order_Of_Setting_Items_And_SelectedIndex_During_Initialization_Should_Not_Matter()
         {
+            using var app = Start();
             var items = new[] { "Foo", "Bar" };
             var target = new SelectingItemsControl();
 
@@ -1015,6 +1016,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
         [Fact]
         public void Order_Of_Setting_Items_And_SelectedItem_During_Initialization_Should_Not_Matter()
         {
+            using var app = Start();
             var items = new[] { "Foo", "Bar" };
             var target = new SelectingItemsControl();
 
@@ -1847,6 +1849,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
         public void Preserves_SelectedItem_When_Items_Changed()
         {
             // Issue #4048
+            using var app = Start();
             var target = new SelectingItemsControl
             {
                 Items = new[] { "foo", "bar", "baz"},
@@ -1867,6 +1870,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
         [Fact]
         public void Setting_SelectedItems_Raises_PropertyChanged()
         {
+            using var app = Start();
             var target = new TestSelector
             {
                 Items = new[] { "foo", "bar", "baz" },
@@ -1895,6 +1899,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
         [Fact]
         public void Setting_Selection_Raises_SelectedItems_PropertyChanged()
         {
+            using var app = Start();
             var target = new TestSelector
             {
                 Items = new[] { "foo", "bar", "baz" },
@@ -2050,6 +2055,13 @@ namespace Avalonia.Controls.UnitTests.Primitives
             }
         }
 
+        private static IDisposable Start()
+        {
+            return UnitTestApplication.Start(new TestServices(
+                fontManagerImpl: new MockFontManagerImpl(),
+                textShaperImpl: new MockTextShaperImpl()));
+        }
+
         private static void Prepare(SelectingItemsControl target)
         {
             var root = new TestRoot

+ 121 - 128
tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs

@@ -170,36 +170,41 @@ namespace Avalonia.Controls.UnitTests.Primitives
         [Fact]
         public void Templated_Children_Should_Be_Styled()
         {
-            using (UnitTestApplication.Start(TestServices.MockStyler))
-            {
-                TestTemplatedControl target;
+            TestTemplatedControl target;
 
-                var root = new TestRoot
+            var root = new TestRoot
+            {
+                Styles =
                 {
-                    Child = target = new TestTemplatedControl
+                    new Style(x => x.Is<Control>())
                     {
-                        Template = new FuncControlTemplate((_, __) =>
+                        Setters =
                         {
-                            return new StackPanel
-                            {
-                                Children =
+                            new Setter(Control.TagProperty, "foo")
+                        }
+                    }
+                },
+                Child = target = new TestTemplatedControl
+                {
+                    Template = new FuncControlTemplate((_, __) =>
+                    {
+                        return new StackPanel
+                        {
+                            Children =
                                 {
                                     new TextBlock
                                     {
                                     }
                                 }
-                            };
-                        }),
-                    }
-                };
+                        };
+                    }),
+                }
+            };
 
-                target.ApplyTemplate();
+            target.ApplyTemplate();
 
-                var styler = Mock.Get(UnitTestApplication.Current.Services.Styler);
-                styler.Verify(x => x.ApplyStyles(It.IsAny<TestTemplatedControl>()), Times.Once());
-                styler.Verify(x => x.ApplyStyles(It.IsAny<StackPanel>()), Times.Once());
-                styler.Verify(x => x.ApplyStyles(It.IsAny<TextBlock>()), Times.Once());
-            }
+            foreach (Control child in target.GetTemplateChildren())
+                Assert.Equal("foo", child.Tag);
         }
 
         [Fact]
@@ -351,166 +356,154 @@ namespace Avalonia.Controls.UnitTests.Primitives
         [Fact]
         public void Removing_From_LogicalTree_Should_Not_Remove_Child()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            Border templateChild = new Border();
+            TestTemplatedControl target;
+            var root = new TestRoot
             {
-                Border templateChild = new Border();
-                TestTemplatedControl target;
-                var root = new TestRoot
+                Styles =
                 {
-                    Styles =
+                    new Style(x => x.OfType<TestTemplatedControl>())
                     {
-                        new Style(x => x.OfType<TestTemplatedControl>())
+                        Setters =
                         {
-                            Setters =
-                            {
-                                new Setter(
-                                    TemplatedControl.TemplateProperty,
-                                    new FuncControlTemplate((_, __) => new Decorator
-                                    {
-                                        Child = new Border(),
-                                    }))
-                            }
+                            new Setter(
+                                TemplatedControl.TemplateProperty,
+                                new FuncControlTemplate((_, __) => new Decorator
+                                {
+                                    Child = new Border(),
+                                }))
                         }
-                    },
-                    Child = target = new TestTemplatedControl()
-                };
+                    }
+                },
+                Child = target = new TestTemplatedControl()
+            };
 
-                Assert.NotNull(target.Template);
-                target.ApplyTemplate();
+            Assert.NotNull(target.Template);
+            target.ApplyTemplate();
 
-                root.Child = null;
+            root.Child = null;
 
-                Assert.Null(target.Template);
-                Assert.IsType<Decorator>(target.GetVisualChildren().Single());
-            }
+            Assert.Null(target.Template);
+            Assert.IsType<Decorator>(target.GetVisualChildren().Single());
         }
 
         [Fact]
         public void Re_adding_To_Same_LogicalTree_Should_Not_Recreate_Template()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            TestTemplatedControl target;
+            var root = new TestRoot
             {
-                TestTemplatedControl target;
-                var root = new TestRoot
+                Styles =
                 {
-                    Styles =
+                    new Style(x => x.OfType<TestTemplatedControl>())
                     {
-                        new Style(x => x.OfType<TestTemplatedControl>())
+                        Setters =
                         {
-                            Setters =
-                            {
-                                new Setter(
-                                    TemplatedControl.TemplateProperty,
-                                    new FuncControlTemplate((_, __) => new Decorator
-                                    {
-                                        Child = new Border(),
-                                    }))
-                            }
+                            new Setter(
+                                TemplatedControl.TemplateProperty,
+                                new FuncControlTemplate((_, __) => new Decorator
+                                {
+                                    Child = new Border(),
+                                }))
                         }
-                    },
-                    Child = target = new TestTemplatedControl()
-                };
+                    }
+                },
+                Child = target = new TestTemplatedControl()
+            };
 
-                Assert.NotNull(target.Template);
-                target.ApplyTemplate();
-                var expected = (Decorator)target.GetVisualChildren().Single();
+            Assert.NotNull(target.Template);
+            target.ApplyTemplate();
+            var expected = (Decorator)target.GetVisualChildren().Single();
 
-                root.Child = null;
-                root.Child = target;
-                target.ApplyTemplate();
+            root.Child = null;
+            root.Child = target;
+            target.ApplyTemplate();
 
-                Assert.Same(expected, target.GetVisualChildren().Single());
-            }
+            Assert.Same(expected, target.GetVisualChildren().Single());
         }
 
         [Fact]
         public void Re_adding_To_Different_LogicalTree_Should_Recreate_Template()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
-            {
-                TestTemplatedControl target;
+            TestTemplatedControl target;
 
-                var root = new TestRoot
+            var root = new TestRoot
+            {
+                Styles =
                 {
-                    Styles =
+                    new Style(x => x.OfType<TestTemplatedControl>())
                     {
-                        new Style(x => x.OfType<TestTemplatedControl>())
+                        Setters =
                         {
-                            Setters =
-                            {
-                                new Setter(
-                                    TemplatedControl.TemplateProperty,
-                                    new FuncControlTemplate((_, __) => new Decorator
-                                    {
-                                        Child = new Border(),
-                                    }))
-                            }
+                            new Setter(
+                                TemplatedControl.TemplateProperty,
+                                new FuncControlTemplate((_, __) => new Decorator
+                                {
+                                    Child = new Border(),
+                                }))
                         }
-                    },
-                    Child = target = new TestTemplatedControl()
-                };
+                    }
+                },
+                Child = target = new TestTemplatedControl()
+            };
 
-                var root2 = new TestRoot
+            var root2 = new TestRoot
+            {
+                Styles =
                 {
-                    Styles =
+                    new Style(x => x.OfType<TestTemplatedControl>())
                     {
-                        new Style(x => x.OfType<TestTemplatedControl>())
+                        Setters =
                         {
-                            Setters =
-                            {
-                                new Setter(
-                                    TemplatedControl.TemplateProperty,
-                                    new FuncControlTemplate((_, __) => new Decorator
-                                    {
-                                        Child = new Border(),
-                                    }))
-                            }
+                            new Setter(
+                                TemplatedControl.TemplateProperty,
+                                new FuncControlTemplate((_, __) => new Decorator
+                                {
+                                    Child = new Border(),
+                                }))
                         }
-                    },
-                };
+                    }
+                },
+            };
 
-                Assert.NotNull(target.Template);
-                target.ApplyTemplate();
+            Assert.NotNull(target.Template);
+            target.ApplyTemplate();
 
-                var expected = (Decorator)target.GetVisualChildren().Single();
+            var expected = (Decorator)target.GetVisualChildren().Single();
 
-                root.Child = null;
-                root2.Child = target;
-                target.ApplyTemplate();
+            root.Child = null;
+            root2.Child = target;
+            target.ApplyTemplate();
 
-                var child = target.GetVisualChildren().Single();
-                Assert.NotNull(target.Template);
-                Assert.NotNull(child);
-                Assert.NotSame(expected, child);
-            }
+            var child = target.GetVisualChildren().Single();
+            Assert.NotNull(target.Template);
+            Assert.NotNull(child);
+            Assert.NotSame(expected, child);
         }
 
         [Fact]
         public void Moving_To_New_LogicalTree_Should_Detach_Attach_Template_Child()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            TestTemplatedControl target;
+            var root = new TestRoot
             {
-                TestTemplatedControl target;
-                var root = new TestRoot
+                Child = target = new TestTemplatedControl
                 {
-                    Child = target = new TestTemplatedControl
-                    {
-                        Template = new FuncControlTemplate((_, __) => new Decorator()),
-                    }
-                };
+                    Template = new FuncControlTemplate((_, __) => new Decorator()),
+                }
+            };
 
-                Assert.NotNull(target.Template);
-                target.ApplyTemplate();
+            Assert.NotNull(target.Template);
+            target.ApplyTemplate();
 
-                var templateChild = (ILogical)target.GetVisualChildren().Single();
-                Assert.True(templateChild.IsAttachedToLogicalTree);
+            var templateChild = (ILogical)target.GetVisualChildren().Single();
+            Assert.True(templateChild.IsAttachedToLogicalTree);
 
-                root.Child = null;
-                Assert.False(templateChild.IsAttachedToLogicalTree);
+            root.Child = null;
+            Assert.False(templateChild.IsAttachedToLogicalTree);
 
-                var newRoot = new TestRoot { Child = target };
-                Assert.True(templateChild.IsAttachedToLogicalTree);
-            }
+            var newRoot = new TestRoot { Child = target };
+            Assert.True(templateChild.IsAttachedToLogicalTree);
         }
 
         [Fact]

+ 12 - 16
tests/Avalonia.Controls.UnitTests/TabControlTests.cs

@@ -227,28 +227,24 @@ namespace Avalonia.Controls.UnitTests
             };
 
             var template = new FuncControlTemplate<TabItem>((x, __) => new Decorator());
-
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            var root = new TestRoot
             {
-                var root = new TestRoot
+                Styles =
                 {
-                    Styles =
+                    new Style(x => x.OfType<TabItem>())
                     {
-                        new Style(x => x.OfType<TabItem>())
+                        Setters =
                         {
-                            Setters =
-                            {
-                                new Setter(TemplatedControl.TemplateProperty, template)
-                            }
+                            new Setter(TemplatedControl.TemplateProperty, template)
                         }
-                    },
-                    Child = new TabControl
-                    {
-                        Template = TabControlTemplate(),
-                        Items = collection,
                     }
-                };
-            }
+                },
+                Child = new TabControl
+                {
+                    Template = TabControlTemplate(),
+                    Items = collection,
+                }
+            };
 
             Assert.Same(collection[0].Template, template);
             Assert.Same(collection[1].Template, template);

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

@@ -77,7 +77,7 @@ namespace Avalonia.Controls.UnitTests
         public void Items_Should_Be_Created_Using_ItemConatinerTheme_If_Present()
         {
             TreeView target;
-            var theme = new ControlTheme();
+            var theme = new ControlTheme(typeof(TreeViewItem));
 
             var root = new TestRoot
             {

+ 11 - 14
tests/Avalonia.Controls.UnitTests/UserControlTests.cs

@@ -13,26 +13,23 @@ namespace Avalonia.Controls.UnitTests
         [Fact]
         public void Should_Be_Styled_As_UserControl()
         {
-            using (UnitTestApplication.Start(TestServices.RealStyler))
+            var target = new UserControl();
+            var root = new TestRoot
             {
-                var target = new UserControl();
-                var root = new TestRoot
+                Styles =
                 {
-                    Styles =
+                    new Style(x => x.OfType<UserControl>())
                     {
-                        new Style(x => x.OfType<UserControl>())
+                        Setters =
                         {
-                            Setters =
-                            {
-                                new Setter(TemplatedControl.TemplateProperty, GetTemplate())
-                            }
+                            new Setter(TemplatedControl.TemplateProperty, GetTemplate())
                         }
-                    },
-                    Child = target,
-                };
+                    }
+                },
+                Child = target,
+            };
 
-                Assert.NotNull(target.Template);
-            }
+            Assert.NotNull(target.Template);
         }
 
         private FuncControlTemplate GetTemplate()

+ 5 - 16
tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs

@@ -23,11 +23,8 @@ namespace Avalonia.Controls.UnitTests.Utils
         {
             using (AvaloniaLocator.EnterScope())
             {
-                var styler = new Mock<Styler>();
-
                 AvaloniaLocator.CurrentMutable
-                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
-                    .Bind<IStyler>().ToConstant(styler.Object);
+                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock());
 
                 var gesture1 = new KeyGesture(Key.A, KeyModifiers.Control);
                 var gesture2 = new KeyGesture(Key.B, KeyModifiers.Control);
@@ -67,13 +64,11 @@ namespace Avalonia.Controls.UnitTests.Utils
         {
             using (AvaloniaLocator.EnterScope())
             {
-                var styler = new Mock<Styler>();
                 var target = new KeyboardDevice();
                 var commandResult = 0;
                 var expectedParameter = 1;
                 AvaloniaLocator.CurrentMutable
-                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
-                    .Bind<IStyler>().ToConstant(styler.Object);
+                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock());
 
                 var gesture = new KeyGesture(Key.A, KeyModifiers.Control);
 
@@ -112,12 +107,10 @@ namespace Avalonia.Controls.UnitTests.Utils
         {
             using (AvaloniaLocator.EnterScope())
             {
-                var styler = new Mock<Styler>();
                 var target = new KeyboardDevice();
                 var isExecuted = false;
                 AvaloniaLocator.CurrentMutable
-                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
-                    .Bind<IStyler>().ToConstant(styler.Object);
+                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock());
 
                 var gesture = new KeyGesture(Key.A, KeyModifiers.Control);
 
@@ -154,12 +147,10 @@ namespace Avalonia.Controls.UnitTests.Utils
         {
             using (AvaloniaLocator.EnterScope())
             {
-                var styler = new Mock<Styler>();
                 var target = new KeyboardDevice();
                 var clickExecutedCount = 0;
                 AvaloniaLocator.CurrentMutable
-                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
-                    .Bind<IStyler>().ToConstant(styler.Object);
+                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock());
 
                 var gesture = new KeyGesture(Key.A, KeyModifiers.Control);
 
@@ -208,13 +199,11 @@ namespace Avalonia.Controls.UnitTests.Utils
         {
             using (AvaloniaLocator.EnterScope())
             {
-                var styler = new Mock<Styler>();
                 var target = new KeyboardDevice();
                 var clickExecutedCount = 0;
                 var commandExecutedCount = 0;
                 AvaloniaLocator.CurrentMutable
-                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
-                    .Bind<IStyler>().ToConstant(styler.Object);
+                    .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock());
 
                 var gesture = new KeyGesture(Key.A, KeyModifiers.Control);
 

+ 6 - 0
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@@ -5,6 +5,7 @@ using System.ComponentModel;
 using System.Globalization;
 using System.Linq;
 using System.Reactive.Subjects;
+using System.Runtime.CompilerServices;
 using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Controls.Presenters;
@@ -26,6 +27,11 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
 {
     public class CompiledBindingExtensionTests
     {
+        static CompiledBindingExtensionTests()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(RelativeSource).TypeHandle);
+        }
+
         [Fact]
         public void ResolvesClrPropertyBasedOnDataContextType()
         {

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

@@ -23,7 +23,6 @@ namespace Avalonia.UnitTests
             platform: new AppBuilder().RuntimePlatform,
             renderInterface: new MockPlatformRenderInterface(),
             standardCursorFactory: Mock.Of<ICursorFactory>(),
-            styler: new Styler(),
             theme: () => CreateSimpleTheme(),
             threadingInterface: Mock.Of<IPlatformThreadingInterface>(x => x.CurrentThreadIsLoopThread == true),
             fontManagerImpl: new MockFontManagerImpl(),
@@ -39,9 +38,6 @@ namespace Avalonia.UnitTests
         public static readonly TestServices MockPlatformWrapper = new TestServices(
             platform: Mock.Of<IRuntimePlatform>());
 
-        public static readonly TestServices MockStyler = new TestServices(
-            styler: Mock.Of<IStyler>());
-
         public static readonly TestServices MockThreadingInterface = new TestServices(
             threadingInterface: Mock.Of<IPlatformThreadingInterface>(x => x.CurrentThreadIsLoopThread == true));
 
@@ -58,9 +54,6 @@ namespace Avalonia.UnitTests
             fontManagerImpl: new MockFontManagerImpl(),
             textShaperImpl: new MockTextShaperImpl());
 
-        public static readonly TestServices RealStyler = new TestServices(
-            styler: new Styler());
-
         public static readonly TestServices TextServices = new TestServices(
             assetLoader: new AssetLoader(),
             renderInterface: new MockPlatformRenderInterface(),
@@ -80,7 +73,6 @@ namespace Avalonia.UnitTests
             IRenderTimer renderLoop = null,
             IScheduler scheduler = null,
             ICursorFactory standardCursorFactory = null,
-            IStyler styler = null,
             Func<IStyle> theme = null,
             IPlatformThreadingInterface threadingInterface = null,
             IFontManagerImpl fontManagerImpl = null,
@@ -101,7 +93,6 @@ namespace Avalonia.UnitTests
             TextShaperImpl = textShaperImpl;
             Scheduler = scheduler;
             StandardCursorFactory = standardCursorFactory;
-            Styler = styler;
             Theme = theme;
             ThreadingInterface = threadingInterface;
             WindowImpl = windowImpl;
@@ -121,7 +112,6 @@ namespace Avalonia.UnitTests
         public ITextShaperImpl TextShaperImpl { get; }
         public IScheduler Scheduler { get; }
         public ICursorFactory StandardCursorFactory { get; }
-        public IStyler Styler { get; }
         public Func<IStyle> Theme { get; }
         public IPlatformThreadingInterface ThreadingInterface { get; }
         public IWindowImpl WindowImpl { get; }
@@ -140,8 +130,7 @@ namespace Avalonia.UnitTests
             IRenderTimer renderLoop = null,
             IScheduler scheduler = null,
             ICursorFactory standardCursorFactory = null,
-            IStyler styler = null,
-            Func<Styles> theme = null,
+            Func<IStyle> theme = null,
             IPlatformThreadingInterface threadingInterface = null,
             IFontManagerImpl fontManagerImpl = null,
             ITextShaperImpl textShaperImpl = null,
@@ -162,7 +151,6 @@ namespace Avalonia.UnitTests
                 textShaperImpl: textShaperImpl ?? TextShaperImpl,
                 scheduler: scheduler ?? Scheduler,
                 standardCursorFactory: standardCursorFactory ?? StandardCursorFactory,
-                styler: styler ?? Styler,
                 theme: theme ?? Theme,
                 threadingInterface: threadingInterface ?? ThreadingInterface,
                 windowingPlatform: windowingPlatform ?? WindowingPlatform,

+ 2 - 3
tests/Avalonia.UnitTests/UnitTestApplication.cs

@@ -68,14 +68,13 @@ namespace Avalonia.UnitTests
                 .Bind<IPlatformThreadingInterface>().ToConstant(Services.ThreadingInterface)
                 .Bind<IScheduler>().ToConstant(Services.Scheduler)
                 .Bind<ICursorFactory>().ToConstant(Services.StandardCursorFactory)
-                .Bind<IStyler>().ToConstant(Services.Styler)
                 .Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform)
                 .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
             var theme = Services.Theme?.Invoke();
 
-            if (theme is Styles styles)
+            if (theme is Style styles)
             {
-                Styles.AddRange(styles);
+                Styles.AddRange(styles.Children);
             }
             else if (theme is not null)
             {