Browse Source

Merge pull request #3073 from MarchingCube/optimize-selectors

Optimize TypeNameAndClassSelector.
pull/3087/head
Steven Kirk 7 years ago
committed by GitHub
parent
commit
1b9099753f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 90
      src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs

90
src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs

@ -18,8 +18,9 @@ namespace Avalonia.Styling
internal class TypeNameAndClassSelector : Selector
{
private readonly Selector _previous;
private readonly Lazy<List<string>> _classes = new Lazy<List<string>>(() => new List<string>());
private Type _targetType;
private Lazy<List<string>> _classes = new Lazy<List<string>>(() => new List<string>());
private string _selectorString;
public static TypeNameAndClassSelector OfType(Selector previous, Type targetType)
@ -27,6 +28,7 @@ namespace Avalonia.Styling
var result = new TypeNameAndClassSelector(previous);
result._targetType = targetType;
result.IsConcreteType = true;
return result;
}
@ -35,6 +37,7 @@ namespace Avalonia.Styling
var result = new TypeNameAndClassSelector(previous);
result._targetType = targetType;
result.IsConcreteType = false;
return result;
}
@ -42,6 +45,7 @@ namespace Avalonia.Styling
{
var result = new TypeNameAndClassSelector(previous);
result.Name = name;
return result;
}
@ -49,6 +53,7 @@ namespace Avalonia.Styling
{
var result = new TypeNameAndClassSelector(previous);
result.Classes.Add(className);
return result;
}
@ -126,9 +131,11 @@ namespace Avalonia.Styling
if (subscribe)
{
var observable = new ClassObserver(control.Classes, _classes.Value);
return new SelectorMatch(observable);
}
else if (!Matches(control.Classes))
if (!AreClassesMatching(control.Classes, Classes))
{
return SelectorMatch.NeverThisInstance;
}
@ -139,21 +146,6 @@ namespace Avalonia.Styling
protected override Selector MovePrevious() => _previous;
private bool Matches(IEnumerable<string> classes)
{
int remaining = Classes.Count;
foreach (var c in classes)
{
if (Classes.Contains(c))
{
--remaining;
}
}
return remaining == 0;
}
private string BuildSelectorString()
{
var builder = new StringBuilder();
@ -199,11 +191,41 @@ namespace Avalonia.Styling
return builder.ToString();
}
private class ClassObserver : LightweightObservableBase<bool>
private static bool AreClassesMatching(IReadOnlyList<string> classes, IList<string> toMatch)
{
readonly IList<string> _match;
IAvaloniaReadOnlyList<string> _classes;
bool _value;
int remainingMatches = toMatch.Count;
int classesCount = classes.Count;
// Early bail out - we can't match if control does not have enough classes.
if (classesCount < remainingMatches)
{
return false;
}
for (var i = 0; i < classesCount; i++)
{
var c = classes[i];
if (toMatch.Contains(c))
{
--remainingMatches;
// Already matched so we can skip checking other classes.
if (remainingMatches == 0)
{
break;
}
}
}
return remainingMatches == 0;
}
private sealed class ClassObserver : LightweightObservableBase<bool>
{
private readonly IList<string> _match;
private readonly IAvaloniaReadOnlyList<string> _classes;
private bool _hasMatch;
public ClassObserver(IAvaloniaReadOnlyList<string> classes, IList<string> match)
{
@ -215,42 +237,32 @@ namespace Avalonia.Styling
protected override void Initialize()
{
_value = GetResult();
_hasMatch = IsMatching();
_classes.CollectionChanged += ClassesChanged;
}
protected override void Subscribed(IObserver<bool> observer, bool first)
{
observer.OnNext(_value);
observer.OnNext(_hasMatch);
}
private void ClassesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action != NotifyCollectionChangedAction.Move)
{
var value = GetResult();
var hasMatch = IsMatching();
if (value != _value)
if (hasMatch != _hasMatch)
{
PublishNext(GetResult());
_value = value;
PublishNext(hasMatch);
_hasMatch = hasMatch;
}
}
}
private bool GetResult()
private bool IsMatching()
{
int remaining = _match.Count;
foreach (var c in _classes)
{
if (_match.Contains(c))
{
--remaining;
}
}
return remaining == 0;
return AreClassesMatching(_classes, _match);
}
}
}

Loading…
Cancel
Save