Browse Source

Initial implementation of Descendent selector.

pull/4/head
Steven Kirk 12 years ago
parent
commit
afdc1e0c42
  1. 20
      Perspex.UnitTests/Styling/SelectorTests_Descendent.cs
  2. 24
      Perspex/Styling/Selector.cs
  3. 50
      Perspex/Styling/Selectors.cs

20
Perspex.UnitTests/Styling/SelectorTests_Descendent.cs

@ -23,10 +23,7 @@ namespace Perspex.UnitTests.Styling
var parent = new Mock<TestLogical1>();
var child = new Mock<TestLogical2>();
parent.Setup(x => x.LogicalChildren).Returns(new[]
{
child.Object,
});
child.Setup(x => x.LogicalParent).Returns(parent.Object);
var selector = new Selector().OfType<TestLogical1>().Descendent().OfType<TestLogical2>();
@ -36,7 +33,16 @@ namespace Perspex.UnitTests.Styling
[TestMethod]
public void Descendent_Matches_Control_When_It_Is_Descendent_OfType()
{
Assert.Fail();
var grandparent = new Mock<TestLogical1>();
var parent = new Mock<TestLogical2>();
var child = new Mock<TestLogical3>();
parent.Setup(x => x.LogicalParent).Returns(grandparent.Object);
child.Setup(x => x.LogicalParent).Returns(parent.Object);
var selector = new Selector().OfType<TestLogical1>().Descendent().OfType<TestLogical3>();
Assert.AreEqual(true, ActivatorValue(selector, child.Object));
}
private static bool ActivatorValue(Match selector, IStyleable control)
@ -51,5 +57,9 @@ namespace Perspex.UnitTests.Styling
public abstract class TestLogical2 : TestLogical
{
}
public abstract class TestLogical3 : TestLogical
{
}
}
}

24
Perspex/Styling/Selector.cs

@ -15,15 +15,18 @@ namespace Perspex.Styling
public class Selector
{
private bool stopTraversal;
private Func<IStyleable, IObservable<bool>> observable;
public Selector()
{
}
public Selector(Selector previous)
public Selector(Selector previous, bool stopTraversal = false)
{
this.Previous = previous;
this.stopTraversal = stopTraversal;
}
public Func<IStyleable, IObservable<bool>> Observable
@ -42,7 +45,7 @@ namespace Perspex.Styling
public Selector Previous
{
get;
set;
private set;
}
public string SelectorString
@ -51,6 +54,11 @@ namespace Perspex.Styling
set;
}
public Selector MovePrevious()
{
return this.stopTraversal ? null : this.Previous;
}
public Activator GetActivator(IStyleable control)
{
List<IObservable<bool>> inputs = new List<IObservable<bool>>();
@ -63,7 +71,7 @@ namespace Perspex.Styling
inputs.Add(selector.Observable(control));
}
selector = selector.Previous;
selector = selector.MovePrevious();
}
return new Activator(inputs);
@ -71,16 +79,14 @@ namespace Perspex.Styling
public override string ToString()
{
Selector match = this;
StringBuilder b = new StringBuilder();
string result = string.Empty;
while (match != null)
if (this.Previous != null)
{
b.Append(match.SelectorString);
match = match.Previous;
result = this.Previous.ToString();
}
return b.ToString();
return result + this.SelectorString;
}
}
}

50
Perspex/Styling/Selectors.cs

@ -7,17 +7,18 @@
namespace Perspex.Styling
{
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using Perspex.Controls;
public static class Selectors
{
public static Selector Class(this Selector match, string name)
public static Selector Class(this Selector previous, string name)
{
Contract.Requires<ArgumentNullException>(match != null);
Contract.Requires<ArgumentNullException>(previous != null);
Contract.Requires<ArgumentNullException>(name != null);
return new Selector(match)
return new Selector(previous)
{
Observable = control => Observable
.Return(control.Classes.Contains(name))
@ -26,39 +27,60 @@ namespace Perspex.Styling
};
}
public static Selector Descendent(this Selector match)
public static Selector Descendent(this Selector previous)
{
throw new NotImplementedException();
return new Selector(previous, stopTraversal: true)
{
SelectorString = " ",
Observable = control =>
{
ILogical c = (ILogical)control;
List<IObservable<bool>> descendentMatches = new List<IObservable<bool>>();
while (c != null)
{
c = c.LogicalParent;
if (c is IStyleable)
{
descendentMatches.Add(previous.Observable((IStyleable)c));
}
}
return new Activator(descendentMatches, ActivatorMode.Or);
},
};
}
public static Selector Id(this Selector match, string id)
public static Selector Id(this Selector previous, string id)
{
Contract.Requires<ArgumentNullException>(match != null);
Contract.Requires<ArgumentNullException>(previous != null);
return new Selector(match)
return new Selector(previous)
{
Observable = control => Observable.Return(control.Id == id),
SelectorString = '#' + id,
};
}
public static Selector OfType<T>(this Selector match) where T : IStyleable
public static Selector OfType<T>(this Selector previous) where T : IStyleable
{
Contract.Requires<ArgumentNullException>(match != null);
Contract.Requires<ArgumentNullException>(previous != null);
return new Selector(match)
return new Selector(previous)
{
Observable = control => Observable.Return(control is T),
SelectorString = typeof(T).Name,
};
}
public static Selector Template(this Selector match)
public static Selector Template(this Selector previous)
{
Contract.Requires<ArgumentNullException>(match != null);
Contract.Requires<ArgumentNullException>(previous != null);
return new Selector(match)
return new Selector(previous)
{
Observable = control => Observable.Return(control.TemplatedParent != null),
SelectorString = " $ ",
};
}

Loading…
Cancel
Save