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
{
private readonly Func<IStyleable, SelectorMatch> _evaluate;
private readonly Type _targetType;
private readonly bool _inTemplate;
private readonly bool _stopTraversal;
private string _description;
/// <summary>
/// Initializes a new instance of the <see cref="Selector"/> class.
/// </summary>
public Selector()
{
_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(
Selector previous,
Func<IStyleable, SelectorMatch> 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;
}
/// <summary>
/// Gets the previous selector.
/// </summary>
public Selector Previous
{
get; }
get;
}
/// <summary>
/// Gets a string representation of the selector.
/// </summary>
public string SelectorString
{
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()
{
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)
{
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()
{
if (_description == null)

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

@ -8,8 +8,16 @@ using System.Reflection;
namespace Perspex.Styling
{
/// <summary>
/// Extension methods for <see cref="Selector"/>.
/// </summary>
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)
{
Contract.Requires<ArgumentNullException>(previous != null);
@ -17,6 +25,12 @@ namespace Perspex.Styling
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)
{
Contract.Requires<ArgumentNullException>(previous != null);
@ -25,6 +39,11 @@ namespace Perspex.Styling
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)
{
Contract.Requires<ArgumentNullException>(previous != null);
@ -32,18 +51,36 @@ namespace Perspex.Styling
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)
{
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
{
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)
{
Contract.Requires<ArgumentNullException>(previous != null);
@ -51,18 +88,38 @@ namespace Perspex.Styling
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)
{
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
{
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)
{
Contract.Requires<ArgumentNullException>(previous != null);
@ -71,6 +128,11 @@ namespace Perspex.Styling
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)
{
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 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<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