Browse Source

Added style caching to Style children.

Extracted out the caching code from `Styles` and reuse for `Style.Children`.
pull/8024/head
Steven Kirk 4 years ago
parent
commit
3fccb14174
  1. 11
      src/Avalonia.Base/Styling/Style.cs
  2. 58
      src/Avalonia.Base/Styling/StyleCache.cs
  3. 41
      src/Avalonia.Base/Styling/Styles.cs

11
src/Avalonia.Base/Styling/Style.cs

@ -16,6 +16,7 @@ namespace Avalonia.Styling
private IResourceDictionary? _resources;
private List<ISetter>? _setters;
private List<IAnimation>? _animations;
private StyleCache? _childCache;
/// <summary>
/// Initializes a new instance of the <see cref="Style"/> class.
@ -124,12 +125,10 @@ namespace Avalonia.Styling
if (_children is not null)
{
foreach (var child in _children)
{
var childResult = child.TryAttach(target, host);
if (childResult > result)
result = childResult;
}
_childCache ??= new StyleCache();
var childResult = _childCache.TryAttach(_children, target, host);
if (childResult > result)
result = childResult;
}
return result;

58
src/Avalonia.Base/Styling/StyleCache.cs

@ -0,0 +1,58 @@
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, IStyleHost? 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;
}
}
}
}

41
src/Avalonia.Base/Styling/Styles.cs

@ -20,7 +20,7 @@ namespace Avalonia.Styling
private readonly AvaloniaList<IStyle> _styles = new AvaloniaList<IStyle>();
private IResourceHost? _owner;
private IResourceDictionary? _resources;
private Dictionary<Type, List<IStyle>?>? _cache;
private StyleCache? _cache;
public Styles()
{
@ -111,43 +111,8 @@ namespace Avalonia.Styling
public SelectorMatchResult TryAttach(IStyleable target, IStyleHost? host)
{
_cache ??= new Dictionary<Type, List<IStyle>?>();
if (_cache.TryGetValue(target.StyleKey, out var cached))
{
if (cached is object)
{
foreach (var style in cached)
{
style.TryAttach(target, host);
}
return SelectorMatchResult.AlwaysThisType;
}
else
{
return SelectorMatchResult.NeverThisType;
}
}
else
{
List<IStyle>? matches = null;
foreach (var child in this)
{
if (child.TryAttach(target, host) != SelectorMatchResult.NeverThisType)
{
matches ??= new List<IStyle>();
matches.Add(child);
}
}
_cache.Add(target.StyleKey, matches);
return matches is null ?
SelectorMatchResult.NeverThisType :
SelectorMatchResult.AlwaysThisType;
}
_cache ??= new StyleCache();
return _cache.TryAttach(this, target, host);
}
/// <inheritdoc/>

Loading…
Cancel
Save