Browse Source

Added an OR mode to Activator.

pull/4/head
Steven Kirk 12 years ago
parent
commit
eb3b6b13b6
  1. 107
      Perspex.UnitTests/Styling/ActivatorTests.cs
  2. 35
      Perspex/Styling/Activator.cs

107
Perspex.UnitTests/Styling/ActivatorTests.cs

@ -15,10 +15,10 @@
public class ActivatorTests
{
[TestMethod]
public void Activator_Should_Follow_Single_Input()
public void Activator_And_Should_Follow_Single_Input()
{
var inputs = new[] { new TestSubject<bool>(false) };
var target = new Activator(inputs);
var target = new Activator(inputs, ActivatorMode.And);
var result = new TestObserver<bool>();
target.Subscribe(result);
@ -34,7 +34,7 @@
}
[TestMethod]
public void Activator_Should_AND_Multiple_Inputs()
public void Activator_And_Should_AND_Multiple_Inputs()
{
var inputs = new[]
{
@ -42,7 +42,7 @@
new TestSubject<bool>(false),
new TestSubject<bool>(true),
};
var target = new Activator(inputs);
var target = new Activator(inputs, ActivatorMode.And);
var result = new TestObserver<bool>();
target.Subscribe(result);
@ -59,7 +59,7 @@
}
[TestMethod]
public void Activator_Should_Unsubscribe_All_When_Input_Completes_On_False()
public void Activator_And_Should_Unsubscribe_All_When_Input_Completes_On_False()
{
var inputs = new[]
{
@ -67,7 +67,7 @@
new TestSubject<bool>(false),
new TestSubject<bool>(true),
};
var target = new Activator(inputs);
var target = new Activator(inputs, ActivatorMode.And);
var result = new TestObserver<bool>();
target.Subscribe(result);
@ -85,7 +85,7 @@
}
[TestMethod]
public void Activator_Should_Not_Unsubscribe_All_When_Input_Completes_On_False()
public void Activator_And_Should_Not_Unsubscribe_All_When_Input_Completes_On_True()
{
var inputs = new[]
{
@ -93,7 +93,7 @@
new TestSubject<bool>(false),
new TestSubject<bool>(true),
};
var target = new Activator(inputs);
var target = new Activator(inputs, ActivatorMode.And);
var result = new TestObserver<bool>();
target.Subscribe(result);
@ -105,5 +105,96 @@
Assert.AreEqual(1, inputs[1].SubscriberCount);
Assert.AreEqual(1, inputs[2].SubscriberCount);
}
[TestMethod]
public void Activator_Or_Should_Follow_Single_Input()
{
var inputs = new[] { new TestSubject<bool>(false) };
var target = new Activator(inputs, ActivatorMode.Or);
var result = new TestObserver<bool>();
target.Subscribe(result);
Assert.IsFalse(result.GetValue());
inputs[0].OnNext(true);
Assert.IsTrue(result.GetValue());
inputs[0].OnNext(false);
Assert.IsFalse(result.GetValue());
inputs[0].OnNext(true);
Assert.IsTrue(result.GetValue());
Assert.AreEqual(1, inputs[0].SubscriberCount);
}
[TestMethod]
public void Activator_Or_Should_OR_Multiple_Inputs()
{
var inputs = new[]
{
new TestSubject<bool>(false),
new TestSubject<bool>(false),
new TestSubject<bool>(true),
};
var target = new Activator(inputs, ActivatorMode.Or);
var result = new TestObserver<bool>();
target.Subscribe(result);
Assert.IsTrue(result.GetValue());
inputs[2].OnNext(false);
Assert.IsFalse(result.GetValue());
inputs[0].OnNext(true);
Assert.IsTrue(result.GetValue());
Assert.AreEqual(1, inputs[0].SubscriberCount);
Assert.AreEqual(1, inputs[1].SubscriberCount);
Assert.AreEqual(1, inputs[2].SubscriberCount);
}
[TestMethod]
public void Activator_Or_Should_Unsubscribe_All_When_Input_Completes_On_True()
{
var inputs = new[]
{
new TestSubject<bool>(false),
new TestSubject<bool>(false),
new TestSubject<bool>(true),
};
var target = new Activator(inputs, ActivatorMode.Or);
var result = new TestObserver<bool>();
target.Subscribe(result);
Assert.IsTrue(result.GetValue());
inputs[2].OnNext(false);
Assert.IsFalse(result.GetValue());
inputs[0].OnNext(true);
Assert.IsTrue(result.GetValue());
inputs[0].OnCompleted();
Assert.AreEqual(0, inputs[0].SubscriberCount);
Assert.AreEqual(0, inputs[1].SubscriberCount);
Assert.AreEqual(0, inputs[2].SubscriberCount);
}
[TestMethod]
public void Activator_Or_Should_Not_Unsubscribe_All_When_Input_Completes_On_False()
{
var inputs = new[]
{
new TestSubject<bool>(false),
new TestSubject<bool>(false),
new TestSubject<bool>(true),
};
var target = new Activator(inputs, ActivatorMode.Or);
var result = new TestObserver<bool>();
target.Subscribe(result);
Assert.IsTrue(result.GetValue());
inputs[2].OnNext(false);
Assert.IsFalse(result.GetValue());
inputs[2].OnCompleted();
Assert.AreEqual(1, inputs[0].SubscriberCount);
Assert.AreEqual(1, inputs[1].SubscriberCount);
Assert.AreEqual(1, inputs[2].SubscriberCount);
}
}
}

35
Perspex/Styling/Activator.cs

@ -11,8 +11,16 @@ namespace Perspex.Styling
using System.Linq;
using System.Reactive.Disposables;
public enum ActivatorMode
{
And,
Or,
}
public class Activator : IObservable<bool>
{
ActivatorMode mode;
List<bool> values = new List<bool>();
List<IDisposable> subscriptions = new List<IDisposable>();
@ -21,10 +29,12 @@ namespace Perspex.Styling
bool last = false;
public Activator(IEnumerable<IObservable<bool>> inputs)
public Activator(IEnumerable<IObservable<bool>> inputs, ActivatorMode mode = ActivatorMode.And)
{
int i = 0;
this.mode = mode;
foreach (IObservable<bool> input in inputs)
{
int iCaptured = i;
@ -53,7 +63,19 @@ namespace Perspex.Styling
{
this.values[index] = value;
bool current = this.values.All(x => x);
bool current;
switch (this.mode)
{
case ActivatorMode.And:
current = this.values.All(x => x);
break;
case ActivatorMode.Or:
current = this.values.Any(x => x);
break;
default:
throw new InvalidOperationException("Invalid Activator mode.");
}
if (current != last)
{
@ -64,10 +86,13 @@ namespace Perspex.Styling
private void Finish(int i)
{
if (!this.values[i])
// If the observable has finished on 'false' and we're in And mode then it will never
// go back to true so we can unsubscribe from all the other subscriptions now.
// Similarly in Or mode; if the completed value is true then we're done.
bool unsubscribe = this.mode == ActivatorMode.And ? !this.values[i] : this.values[i];
if (unsubscribe)
{
// If the observable has finished on 'false' then it will never go back to true
// so we can unsubscribe from all the other subscriptions now.
foreach (IDisposable subscription in this.subscriptions)
{
subscription.Dispose();

Loading…
Cancel
Save