Browse Source

Return TargetType from Selector.

pull/297/head
Steven Kirk 11 years ago
parent
commit
ba226d47a6
  1. 49
      src/Perspex.Styling/Styling/Selector.cs
  2. 66
      src/Perspex.Styling/Styling/Selectors.cs
  3. 62
      tests/Perspex.Styling.UnitTests/SelectorTests_Multiple.cs

49
src/Perspex.Styling/Styling/Selector.cs

@ -37,22 +37,33 @@ namespace Perspex.Styling
public class Selector public class Selector
{ {
private readonly Func<IStyleable, SelectorMatch> _evaluate; private readonly Func<IStyleable, SelectorMatch> _evaluate;
private readonly Type _targetType;
private readonly bool _inTemplate; private readonly bool _inTemplate;
private readonly bool _stopTraversal; private readonly bool _stopTraversal;
private string _description; private string _description;
/// <summary>
/// Initializes a new instance of the <see cref="Selector"/> class.
/// </summary>
public Selector() public Selector()
{ {
_evaluate = _ => SelectorMatch.True; _evaluate = _ => SelectorMatch.True;
} }
/// <summary>
/// Initializes a new instance of the <see cref="Selector"/> class.
/// </summary>
/// <param name="previous">The previous selector.</param>
/// <param name="evaluate">The evaluator function.</param>
/// <param name="selectorString">The string representation of the selector.</param>
/// <param name="targetType">The target type, if available.</param>
/// <param name="inTemplate">Whether to match in a control template.</param>
/// <param name="stopTraversal">Whether to stop traversal at this point.</param>
public Selector( public Selector(
Selector previous, Selector previous,
Func<IStyleable, SelectorMatch> evaluate, Func<IStyleable, SelectorMatch> evaluate,
string selectorString, string selectorString,
Type targetType = null,
bool inTemplate = false, bool inTemplate = false,
bool stopTraversal = false) bool stopTraversal = false)
: this() : this()
@ -62,25 +73,49 @@ namespace Perspex.Styling
Previous = previous; Previous = previous;
_evaluate = evaluate; _evaluate = evaluate;
SelectorString = selectorString; SelectorString = selectorString;
_targetType = targetType;
_inTemplate = inTemplate || previous._inTemplate; _inTemplate = inTemplate || previous._inTemplate;
_stopTraversal = stopTraversal; _stopTraversal = stopTraversal;
} }
/// <summary>
/// Gets the previous selector.
/// </summary>
public Selector Previous public Selector Previous
{ {
get; } get;
}
/// <summary>
/// Gets a string representation of the selector.
/// </summary>
public string SelectorString public string SelectorString
{ {
get; get;
set;
} }
/// <summary>
/// Gets the target type of the selector, if available.
/// </summary>
public Type TargetType
{
get { return _targetType ?? MovePrevious()?.TargetType; }
}
/// <summary>
/// Returns the previous selector if traversal is not stopped.
/// </summary>
/// <returns>The previous selector.</returns>
public Selector MovePrevious() public Selector MovePrevious()
{ {
return _stopTraversal ? null : Previous; return _stopTraversal ? null : Previous;
} }
/// <summary>
/// Tries to match the selector with a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>A <see cref="SelectorMatch"/>.</returns>
public SelectorMatch Match(IStyleable control) public SelectorMatch Match(IStyleable control)
{ {
List<IObservable<bool>> inputs = new List<IObservable<bool>>(); List<IObservable<bool>> inputs = new List<IObservable<bool>>();
@ -117,6 +152,10 @@ namespace Perspex.Styling
} }
} }
/// <summary>
/// Gets a string representation of the selector.
/// </summary>
/// <returns>The string representation of the selector.</returns>
public override string ToString() public override string ToString()
{ {
if (_description == null) if (_description == null)

66
src/Perspex.Styling/Styling/Selectors.cs

@ -8,8 +8,16 @@ using System.Reflection;
namespace Perspex.Styling namespace Perspex.Styling
{ {
/// <summary>
/// Extension methods for <see cref="Selector"/>.
/// </summary>
public static class Selectors public static class Selectors
{ {
/// <summary>
/// Returns a selector which matches a previous selector's child.
/// </summary>
/// <param name="previous">The previous selector.</param>
/// <returns>The selector.</returns>
public static Selector Child(this Selector previous) public static Selector Child(this Selector previous)
{ {
Contract.Requires<ArgumentNullException>(previous != null); Contract.Requires<ArgumentNullException>(previous != null);
@ -17,6 +25,12 @@ namespace Perspex.Styling
return new Selector(previous, x => MatchChild(x, previous), " < ", stopTraversal: true); return new Selector(previous, x => MatchChild(x, previous), " < ", stopTraversal: true);
} }
/// <summary>
/// Returns a selector which matches a control's style class.
/// </summary>
/// <param name="previous">The previous selector.</param>
/// <param name="name">The name of the style class.</param>
/// <returns>The selector.</returns>
public static Selector Class(this Selector previous, string name) public static Selector Class(this Selector previous, string name)
{ {
Contract.Requires<ArgumentNullException>(previous != null); Contract.Requires<ArgumentNullException>(previous != null);
@ -25,6 +39,11 @@ namespace Perspex.Styling
return new Selector(previous, x => MatchClass(x, name), name[0] == ':' ? name : '.' + name); return new Selector(previous, x => MatchClass(x, name), name[0] == ':' ? name : '.' + name);
} }
/// <summary>
/// Returns a selector which matches a descendent of a previous selector.
/// </summary>
/// <param name="previous">The previous selector.</param>
/// <returns>The selector.</returns>
public static Selector Descendent(this Selector previous) public static Selector Descendent(this Selector previous)
{ {
Contract.Requires<ArgumentNullException>(previous != null); Contract.Requires<ArgumentNullException>(previous != null);
@ -32,18 +51,36 @@ namespace Perspex.Styling
return new Selector(previous, x => MatchDescendent(x, previous), " ", stopTraversal: true); return new Selector(previous, x => MatchDescendent(x, previous), " ", stopTraversal: true);
} }
/// <summary>
/// Returns a selector which matches a type or a derived type.
/// </summary>
/// <param name="previous">The previous selector.</param>
/// <param name="type">The type.</param>
/// <returns>The selector.</returns>
public static Selector Is(this Selector previous, Type type) public static Selector Is(this Selector previous, Type type)
{ {
Contract.Requires<ArgumentNullException>(previous != null); Contract.Requires<ArgumentNullException>(previous != null);
return new Selector(previous, x => MatchIs(x, type), type.Name); return new Selector(previous, x => MatchIs(x, type), type.Name, type);
} }
/// <summary>
/// Returns a selector which matches a type or a derived type.
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <param name="previous">The previous selector.</param>
/// <returns>The selector.</returns>
public static Selector Is<T>(this Selector previous) where T : IStyleable public static Selector Is<T>(this Selector previous) where T : IStyleable
{ {
return previous.Is(typeof(T)); return previous.Is(typeof(T));
} }
/// <summary>
/// Returns a selector which matches a control's Name.
/// </summary>
/// <param name="previous">The previous selector.</param>
/// <param name="name">The name.</param>
/// <returns>The selector.</returns>
public static Selector Name(this Selector previous, string name) public static Selector Name(this Selector previous, string name)
{ {
Contract.Requires<ArgumentNullException>(previous != null); Contract.Requires<ArgumentNullException>(previous != null);
@ -51,18 +88,38 @@ namespace Perspex.Styling
return new Selector(previous, x => MatchName(x, name), '#' + name); return new Selector(previous, x => MatchName(x, name), '#' + name);
} }
/// <summary>
/// Returns a selector which matches a type.
/// </summary>
/// <param name="previous">The previous selector.</param>
/// <param name="type">The type.</param>
/// <returns>The selector.</returns>
public static Selector OfType(this Selector previous, Type type) public static Selector OfType(this Selector previous, Type type)
{ {
Contract.Requires<ArgumentNullException>(previous != null); Contract.Requires<ArgumentNullException>(previous != null);
return new Selector(previous, x => MatchOfType(x, type), type.Name); return new Selector(previous, x => MatchOfType(x, type), type.Name, type);
} }
/// <summary>
/// Returns a selector which matches a type.
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <param name="previous">The previous selector.</param>
/// <returns>The selector.</returns>
public static Selector OfType<T>(this Selector previous) where T : IStyleable public static Selector OfType<T>(this Selector previous) where T : IStyleable
{ {
return previous.OfType(typeof(T)); return previous.OfType(typeof(T));
} }
/// <summary>
/// Returns a selector which matches a control with the specified property value.
/// </summary>
/// <typeparam name="T">The property type.</typeparam>
/// <param name="previous">The previous selector.</param>
/// <param name="property">The property.</param>
/// <param name="value">The property value.</param>
/// <returns>The selector.</returns>
public static Selector PropertyEquals<T>(this Selector previous, PerspexProperty<T> property, object value) public static Selector PropertyEquals<T>(this Selector previous, PerspexProperty<T> property, object value)
{ {
Contract.Requires<ArgumentNullException>(previous != null); Contract.Requires<ArgumentNullException>(previous != null);
@ -71,6 +128,11 @@ namespace Perspex.Styling
return new Selector(previous, x => MatchPropertyEquals(x, property, value), $"[{property.Name}={value}]"); return new Selector(previous, x => MatchPropertyEquals(x, property, value), $"[{property.Name}={value}]");
} }
/// <summary>
/// Returns a selector which enters a lookless control's template.
/// </summary>
/// <param name="previous">The previous selector.</param>
/// <returns>The selector.</returns>
public static Selector Template(this Selector previous) public static Selector Template(this Selector previous)
{ {
Contract.Requires<ArgumentNullException>(previous != null); Contract.Requires<ArgumentNullException>(previous != null);

62
tests/Perspex.Styling.UnitTests/SelectorTests_Multiple.cs

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Perspex.Controls; using Perspex.Controls;
using Perspex.Controls.Templates; using Perspex.Controls.Templates;
using Perspex.Styling;
using Xunit; using Xunit;
namespace Perspex.Styling.UnitTests namespace Perspex.Styling.UnitTests
@ -50,5 +49,66 @@ namespace Perspex.Styling.UnitTests
control.Classes.Remove("foo"); control.Classes.Remove("foo");
Assert.Equal(new[] { false, true, false }, values); Assert.Equal(new[] { false, true, false }, values);
} }
[Fact]
public void TargetType_OfType()
{
var selector = new Selector().OfType<Button>();
Assert.Equal(typeof(Button), selector.TargetType);
}
[Fact]
public void TargetType_OfType_Class()
{
var selector = new Selector()
.OfType<Button>()
.Class("foo");
Assert.Equal(typeof(Button), selector.TargetType);
}
[Fact]
public void TargetType_Is_Class()
{
var selector = new Selector()
.Is<Button>()
.Class("foo");
Assert.Equal(typeof(Button), selector.TargetType);
}
[Fact]
public void TargetType_Child()
{
var selector = new Selector()
.OfType<Button>()
.Child()
.OfType<TextBlock>();
Assert.Equal(typeof(TextBlock), selector.TargetType);
}
[Fact]
public void TargetType_Descendent()
{
var selector = new Selector()
.OfType<Button>()
.Descendent()
.OfType<TextBlock>();
Assert.Equal(typeof(TextBlock), selector.TargetType);
}
[Fact]
public void TargetType_Template()
{
var selector = new Selector()
.OfType<Button>()
.Template()
.OfType<TextBlock>();
Assert.Equal(typeof(TextBlock), selector.TargetType);
}
} }
} }

Loading…
Cancel
Save