Browse Source

Made all tests pass again.

pull/4/head
Steven Kirk 12 years ago
parent
commit
012a010ba3
  1. 92
      Perspex.UnitTests/PerspexObjectTests.cs
  2. 2
      Perspex.UnitTests/StyleTests.cs
  3. 35
      Perspex/PerspexObject.cs
  4. 51
      Perspex/PriorityValue.cs
  5. 82
      Perspex/Styling/StyleBinding.cs

92
Perspex.UnitTests/PerspexObjectTests.cs

@ -261,7 +261,7 @@ namespace Perspex.UnitTests
Class1 source = new Class1();
source.SetValue(Class1.FooProperty, "initial");
target.SetValue((PerspexProperty)Class1.FooProperty, source.GetObservable(Class1.FooProperty));
target.Bind((PerspexProperty)Class1.FooProperty, source.GetObservable(Class1.FooProperty));
Assert.AreEqual("initial", target.GetValue(Class1.FooProperty));
}
@ -321,93 +321,33 @@ namespace Perspex.UnitTests
[TestMethod]
public void StyleBinding_Overrides_Default_Value()
{
throw new NotImplementedException();
//Class1 target = new Class1();
Class1 target = new Class1();
//target.Bind(Class1.FooProperty, "stylevalue", Observable.Return(true));
target.Bind(Class1.FooProperty, this.Single("stylevalue"), BindingPriority.Style);
//Assert.AreEqual("stylevalue", target.GetValue(Class1.FooProperty));
Assert.AreEqual("stylevalue", target.GetValue(Class1.FooProperty));
}
[TestMethod]
public void StyleBinding_Doesnt_Override_Local_Value()
{
throw new NotImplementedException();
//Class1 target = new Class1();
//target.SetValue(Class1.FooProperty, "newvalue");
//target.SetValue(Class1.FooProperty, "stylevalue", Observable.Return(true));
//Assert.AreEqual("newvalue", target.GetValue(Class1.FooProperty));
}
[TestMethod]
public void StyleBinding_Deactivated_Doesnt_Override_Default_Value()
{
throw new NotImplementedException();
//Class1 target = new Class1();
//target.SetValue(Class1.FooProperty, "stylevalue", Observable.Return(false));
//Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty));
}
[TestMethod]
public void StyleBinding_Toggles_On_Activation()
{
throw new NotImplementedException();
//Class1 target = new Class1();
//Subject<bool> source = new Subject<bool>();
//target.SetValue(Class1.FooProperty, "stylevalue", source);
//Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty));
//source.OnNext(true);
//Assert.AreEqual("stylevalue", target.GetValue(Class1.FooProperty));
//source.OnNext(false);
//Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty));
}
[TestMethod]
public void StyleBinding_Detaches_OnCompleted()
{
throw new NotImplementedException();
//Class1 target = new Class1();
Class1 target = new Class1();
//Subject<bool> source = new Subject<bool>();
//target.SetValue(Class1.FooProperty, "stylevalue", source);
target.SetValue(Class1.FooProperty, "newvalue");
target.Bind(Class1.FooProperty, this.Single("stylevalue"), BindingPriority.Style);
//Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty));
//source.OnNext(true);
//Assert.AreEqual("stylevalue", target.GetValue(Class1.FooProperty));
//source.OnCompleted();
//Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty));
Assert.AreEqual("newvalue", target.GetValue(Class1.FooProperty));
}
[TestMethod]
public void Later_StyleBindings_Have_Precedence()
/// <summary>
/// Returns an observable that returns a single value but does not complete.
/// </summary>
/// <typeparam name="T">The type of the observable.</typeparam>
/// <param name="value">The value.</param>
/// <returns>The observable.</returns>
private IObservable<T> Single<T>(T value)
{
throw new NotImplementedException();
//Class1 target = new Class1();
//Subject<bool> source1 = new Subject<bool>();
//Subject<bool> source2 = new Subject<bool>();
//target.SetValue(Class1.FooProperty, "style1", source1);
//target.SetValue(Class1.FooProperty, "style2", source2);
//Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty));
//source1.OnNext(true);
//Assert.AreEqual("style1", target.GetValue(Class1.FooProperty));
//source2.OnNext(true);
//Assert.AreEqual("style2", target.GetValue(Class1.FooProperty));
//source1.OnNext(false);
//Assert.AreEqual("style2", target.GetValue(Class1.FooProperty));
//source2.OnNext(false);
//Assert.AreEqual("foodefault", target.GetValue(Class1.FooProperty));
//source2.OnNext(true);
//Assert.AreEqual("style2", target.GetValue(Class1.FooProperty));
//source1.OnNext(true);
//Assert.AreEqual("style2", target.GetValue(Class1.FooProperty));
return Observable.Never<T>().StartWith(value);
}
private class Class1 : PerspexObject

2
Perspex.UnitTests/StyleTests.cs

@ -105,7 +105,7 @@ namespace Perspex.UnitTests
target.Classes.Add("foo");
target.Classes.Remove("foo");
CollectionAssert.AreEqual(new[] { "foodefault", "Bar", "foodefault" }, values);
CollectionAssert.AreEqual(new[] { "foodefault", "Foo", "Bar", "foodefault" }, values);
}
private class Class1 : Control

35
Perspex/PerspexObject.cs

@ -120,7 +120,6 @@ namespace Perspex
/// </summary>
public void BeginDeferChanges()
{
throw new NotImplementedException();
//foreach (PriorityValue v in this.values.Values)
//{
// v.BeginDeferChanges();
@ -138,7 +137,6 @@ namespace Perspex
/// </summary>
public void EndDeferChanges()
{
throw new NotImplementedException();
//foreach (PriorityValue v in this.values.Values)
//{
// v.EndDeferChanges();
@ -397,6 +395,7 @@ namespace Perspex
{
Contract.Requires<NullReferenceException>(property != null);
const int priority = (int)BindingPriority.LocalValue;
PriorityValue v;
if (!this.values.TryGetValue(property, out v))
@ -410,8 +409,8 @@ namespace Perspex
this.values.Add(property, v);
}
throw new NotImplementedException();
//v.SetLocalValue(value);
v.Clear(priority);
v.Add(Observable.Never<object>().StartWith(value), priority);
}
/// <summary>
@ -439,7 +438,22 @@ namespace Perspex
IObservable<object> source,
BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
Contract.Requires<NullReferenceException>(property != null);
PriorityValue v;
if (!this.values.TryGetValue(property, out v))
{
v = this.CreatePriorityValue(property);
this.values.Add(property, v);
}
if (priority == BindingPriority.LocalValue)
{
v.Clear((int)priority);
}
v.Add(source, (int)priority);
this.Log().Debug(string.Format(
"Bound value of {0}.{1} (#{2:x8})",
@ -465,17 +479,6 @@ namespace Perspex
this.Bind((PerspexProperty)property, (IObservable<object>)source, priority);
}
private static IObservable<object> BoxObservable<T>(IObservable<T> observable)
{
return Observable.Create<object>(observer =>
{
return observable.Subscribe(value =>
{
observer.OnNext(value);
});
});
}
private PriorityValue CreatePriorityValue(PerspexProperty property)
{
PriorityValue result = new PriorityValue();

51
Perspex/PriorityValue.cs

@ -8,7 +8,6 @@ namespace Perspex
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Subjects;
@ -101,12 +100,39 @@ namespace Perspex
return Disposable.Create(() =>
{
entry.Dispose();
this.bindings.Remove(entry);
this.UpdateValue();
this.Remove(entry);
});
}
/// <summary>
/// Removes all bindings with the specified priority.
/// </summary>
/// <param name="priority">The priority.</param>
public void Clear(int priority)
{
LinkedListNode<BindingEntry> item = this.bindings.First;
bool removed = false;
while (item != null && item.Value.Priority <= priority)
{
LinkedListNode<BindingEntry> next = item.Next;
if (item.Value.Priority == priority)
{
item.Value.Dispose();
this.bindings.Remove(item);
removed = true;
}
item = next;
}
if (removed && priority <= this.valuePriority)
{
this.UpdateValue();
}
}
/// <summary>
/// Gets the currently active bindings on this object.
/// </summary>
@ -134,9 +160,7 @@ namespace Perspex
/// <param name="changed">The completed entry.</param>
private void EntryCompleted(BindingEntry entry)
{
entry.Dispose();
this.bindings.Remove(entry);
this.UpdateValue();
this.Remove(entry);
}
/// <summary>
@ -157,6 +181,17 @@ namespace Perspex
}
}
/// <summary>
/// Removes the specified binding entry and updates the current value.
/// </summary>
/// <param name="entry">The binding entry to remove.</param>
private void Remove(BindingEntry entry)
{
entry.Dispose();
this.bindings.Remove(entry);
this.UpdateValue();
}
/// <summary>
/// Updates the current value.
/// </summary>
@ -170,6 +205,8 @@ namespace Perspex
return;
}
}
this.SetValue(PerspexProperty.UnsetValue, int.MaxValue);
}
/// <summary>

82
Perspex/Styling/StyleBinding.cs

@ -1,5 +1,5 @@
// -----------------------------------------------------------------------
// <copyright file="ActivatedBinding.cs" company="Tricycle">
// <copyright file="StyleBinding.cs" company="Tricycle">
// Copyright 2013 Tricycle. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
@ -7,79 +7,71 @@
namespace Perspex.Styling
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Subjects;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Provides an observable for a style.
/// </summary>
/// <remarks>
/// This class takes an activator and a value. The activator is an observable which produces
/// a bool. When the activator produces true, this observable will produce <see cref="Value"/>.
/// When the activator produces false (and before the activator returns a value) it will
/// produce <see cref="PerspexProperty.UnsetValue"/>.
/// </remarks>
internal class StyleBinding : IObservable<object>, IObservableDescription
{
private List<IObserver<object>> observers = new List<IObserver<object>>();
/// <summary>
/// The subject that provides the observable implementation.
/// </summary>
private BehaviorSubject<object> subject = new BehaviorSubject<object>(PerspexProperty.UnsetValue);
/// <summary>
/// Initializes a new instance of the <see cref="StyleBinding"/> class.
/// </summary>
/// <param name="activator">The activator.</param>
/// <param name="activatedValue">The activated value.</param>
/// <param name="description">The binding description.</param>
public StyleBinding(
StyleActivator activator,
IObservable<bool> activator,
object activatedValue,
string description)
{
this.Activator = activator;
this.ActivatedValue = activatedValue;
this.Description = description;
this.Activator.Subscribe(
active => this.OnNext(active ? this.ActivatedValue : PerspexProperty.UnsetValue),
error => this.OnError(error),
() => this.OnCompleted());
}
public StyleActivator Activator
{
get;
private set;
activator.Subscribe(
active => this.subject.OnNext(active ? this.ActivatedValue : PerspexProperty.UnsetValue),
error => this.subject.OnError(error),
() => this.subject.OnCompleted());
}
/// <summary>
/// Gets a description of the binding.
/// </summary>
public string Description
{
get;
private set;
}
/// <summary>
/// Gets the activated value.
/// </summary>
public object ActivatedValue
{
get;
private set;
}
/// <summary>
/// Notifies the provider that an observer is to receive notifications.
/// </summary>
/// <param name="observer">The observer.</param>
/// <returns>IDisposable object used to unsubscribe from the observable sequence.</returns>
public IDisposable Subscribe(IObserver<object> observer)
{
Contract.Requires<NullReferenceException>(observer != null);
this.observers.Add(observer);
return Disposable.Create(() => this.observers.Remove(observer));
}
private void OnCompleted()
{
foreach (var observer in this.observers)
{
observer.OnCompleted();
}
}
private void OnError(Exception error)
{
foreach (var observer in this.observers)
{
observer.OnError(error);
}
}
private void OnNext(object value)
{
foreach (var observer in this.observers)
{
observer.OnNext(value);
}
return this.subject.Subscribe(observer);
}
}
}

Loading…
Cancel
Save