From ba226d47a681d18fa1f2d58b354e7827102b50fd Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 19 Oct 2015 20:14:38 +0200 Subject: [PATCH] Return TargetType from Selector. --- src/Perspex.Styling/Styling/Selector.cs | 49 ++++++++++++-- src/Perspex.Styling/Styling/Selectors.cs | 66 ++++++++++++++++++- .../SelectorTests_Multiple.cs | 62 ++++++++++++++++- 3 files changed, 169 insertions(+), 8 deletions(-) diff --git a/src/Perspex.Styling/Styling/Selector.cs b/src/Perspex.Styling/Styling/Selector.cs index 7df3f77512..3ae9feda4c 100644 --- a/src/Perspex.Styling/Styling/Selector.cs +++ b/src/Perspex.Styling/Styling/Selector.cs @@ -37,22 +37,33 @@ namespace Perspex.Styling public class Selector { private readonly Func _evaluate; - + private readonly Type _targetType; private readonly bool _inTemplate; - private readonly bool _stopTraversal; - private string _description; + /// + /// Initializes a new instance of the class. + /// public Selector() { _evaluate = _ => SelectorMatch.True; } + /// + /// Initializes a new instance of the class. + /// + /// The previous selector. + /// The evaluator function. + /// The string representation of the selector. + /// The target type, if available. + /// Whether to match in a control template. + /// Whether to stop traversal at this point. public Selector( Selector previous, Func evaluate, string selectorString, + Type targetType = null, bool inTemplate = false, bool stopTraversal = false) : this() @@ -62,25 +73,49 @@ namespace Perspex.Styling Previous = previous; _evaluate = evaluate; SelectorString = selectorString; + _targetType = targetType; _inTemplate = inTemplate || previous._inTemplate; _stopTraversal = stopTraversal; } + /// + /// Gets the previous selector. + /// public Selector Previous { - get; } + get; + } + /// + /// Gets a string representation of the selector. + /// public string SelectorString { get; - set; } + /// + /// Gets the target type of the selector, if available. + /// + public Type TargetType + { + get { return _targetType ?? MovePrevious()?.TargetType; } + } + + /// + /// Returns the previous selector if traversal is not stopped. + /// + /// The previous selector. public Selector MovePrevious() { return _stopTraversal ? null : Previous; } + /// + /// Tries to match the selector with a control. + /// + /// The control. + /// A . public SelectorMatch Match(IStyleable control) { List> inputs = new List>(); @@ -117,6 +152,10 @@ namespace Perspex.Styling } } + /// + /// Gets a string representation of the selector. + /// + /// The string representation of the selector. public override string ToString() { if (_description == null) diff --git a/src/Perspex.Styling/Styling/Selectors.cs b/src/Perspex.Styling/Styling/Selectors.cs index fc924632ec..3c70ce3002 100644 --- a/src/Perspex.Styling/Styling/Selectors.cs +++ b/src/Perspex.Styling/Styling/Selectors.cs @@ -8,8 +8,16 @@ using System.Reflection; namespace Perspex.Styling { + /// + /// Extension methods for . + /// public static class Selectors { + /// + /// Returns a selector which matches a previous selector's child. + /// + /// The previous selector. + /// The selector. public static Selector Child(this Selector previous) { Contract.Requires(previous != null); @@ -17,6 +25,12 @@ namespace Perspex.Styling return new Selector(previous, x => MatchChild(x, previous), " < ", stopTraversal: true); } + /// + /// Returns a selector which matches a control's style class. + /// + /// The previous selector. + /// The name of the style class. + /// The selector. public static Selector Class(this Selector previous, string name) { Contract.Requires(previous != null); @@ -25,6 +39,11 @@ namespace Perspex.Styling return new Selector(previous, x => MatchClass(x, name), name[0] == ':' ? name : '.' + name); } + /// + /// Returns a selector which matches a descendent of a previous selector. + /// + /// The previous selector. + /// The selector. public static Selector Descendent(this Selector previous) { Contract.Requires(previous != null); @@ -32,18 +51,36 @@ namespace Perspex.Styling return new Selector(previous, x => MatchDescendent(x, previous), " ", stopTraversal: true); } + /// + /// Returns a selector which matches a type or a derived type. + /// + /// The previous selector. + /// The type. + /// The selector. public static Selector Is(this Selector previous, Type type) { Contract.Requires(previous != null); - return new Selector(previous, x => MatchIs(x, type), type.Name); + return new Selector(previous, x => MatchIs(x, type), type.Name, type); } + /// + /// Returns a selector which matches a type or a derived type. + /// + /// The type. + /// The previous selector. + /// The selector. public static Selector Is(this Selector previous) where T : IStyleable { return previous.Is(typeof(T)); } + /// + /// Returns a selector which matches a control's Name. + /// + /// The previous selector. + /// The name. + /// The selector. public static Selector Name(this Selector previous, string name) { Contract.Requires(previous != null); @@ -51,18 +88,38 @@ namespace Perspex.Styling return new Selector(previous, x => MatchName(x, name), '#' + name); } + /// + /// Returns a selector which matches a type. + /// + /// The previous selector. + /// The type. + /// The selector. public static Selector OfType(this Selector previous, Type type) { Contract.Requires(previous != null); - return new Selector(previous, x => MatchOfType(x, type), type.Name); + return new Selector(previous, x => MatchOfType(x, type), type.Name, type); } + /// + /// Returns a selector which matches a type. + /// + /// The type. + /// The previous selector. + /// The selector. public static Selector OfType(this Selector previous) where T : IStyleable { return previous.OfType(typeof(T)); } + /// + /// Returns a selector which matches a control with the specified property value. + /// + /// The property type. + /// The previous selector. + /// The property. + /// The property value. + /// The selector. public static Selector PropertyEquals(this Selector previous, PerspexProperty property, object value) { Contract.Requires(previous != null); @@ -71,6 +128,11 @@ namespace Perspex.Styling return new Selector(previous, x => MatchPropertyEquals(x, property, value), $"[{property.Name}={value}]"); } + /// + /// Returns a selector which enters a lookless control's template. + /// + /// The previous selector. + /// The selector. public static Selector Template(this Selector previous) { Contract.Requires(previous != null); diff --git a/tests/Perspex.Styling.UnitTests/SelectorTests_Multiple.cs b/tests/Perspex.Styling.UnitTests/SelectorTests_Multiple.cs index 189fc98670..0f14820f59 100644 --- a/tests/Perspex.Styling.UnitTests/SelectorTests_Multiple.cs +++ b/tests/Perspex.Styling.UnitTests/SelectorTests_Multiple.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using Perspex.Controls; using Perspex.Controls.Templates; -using Perspex.Styling; using Xunit; namespace Perspex.Styling.UnitTests @@ -50,5 +49,66 @@ namespace Perspex.Styling.UnitTests control.Classes.Remove("foo"); Assert.Equal(new[] { false, true, false }, values); } + + [Fact] + public void TargetType_OfType() + { + var selector = new Selector().OfType