4 changed files with 327 additions and 146 deletions
@ -0,0 +1,181 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PriorityValue.cs" company="Steven Kirk">
|
|||
// Copyright 2014 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics.Contracts; |
|||
using System.Linq; |
|||
using System.Reactive.Disposables; |
|||
|
|||
internal class PriorityValue : IObservable<Tuple<object, object>> |
|||
{ |
|||
private object localValue = PerspexProperty.UnsetValue; |
|||
|
|||
private IDisposable localBinding; |
|||
|
|||
private object lastValue = PerspexProperty.UnsetValue; |
|||
|
|||
private List<StyleEntry> styles = new List<StyleEntry>(); |
|||
|
|||
private List<IObserver<Tuple<object, object>>> observers = |
|||
new List<IObserver<Tuple<object, object>>>(); |
|||
|
|||
public object LocalValue |
|||
{ |
|||
get |
|||
{ |
|||
return this.localValue; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
if (!object.Equals(this.localValue, value)) |
|||
{ |
|||
this.localValue = value; |
|||
this.Push(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void ClearLocalBinding() |
|||
{ |
|||
if (this.localBinding != null) |
|||
{ |
|||
this.localBinding.Dispose(); |
|||
} |
|||
} |
|||
|
|||
public void SetLocalValue(object value) |
|||
{ |
|||
if (this.localBinding != null) |
|||
{ |
|||
this.localBinding.Dispose(); |
|||
} |
|||
|
|||
this.LocalValue = value; |
|||
} |
|||
|
|||
public void SetLocalBinding(IObservable<object> binding) |
|||
{ |
|||
if (this.localBinding != null) |
|||
{ |
|||
this.localBinding.Dispose(); |
|||
} |
|||
|
|||
this.localBinding = binding.Subscribe(value => this.LocalValue = value); |
|||
} |
|||
|
|||
public void AddStyle(object value) |
|||
{ |
|||
StyleEntry entry = new StyleEntry(value); |
|||
|
|||
this.styles.Add(entry); |
|||
|
|||
if (this.localValue == PerspexProperty.UnsetValue) |
|||
{ |
|||
this.Push(); |
|||
} |
|||
} |
|||
|
|||
public void AddStyle(IObservable<bool> activator, object value) |
|||
{ |
|||
Contract.Requires<NullReferenceException>(activator != null); |
|||
|
|||
StyleEntry entry = new StyleEntry(activator, value, this.Push, e => this.styles.Remove(e)); |
|||
|
|||
this.styles.Add(entry); |
|||
|
|||
if (this.localValue == PerspexProperty.UnsetValue) |
|||
{ |
|||
this.Push(); |
|||
} |
|||
} |
|||
|
|||
public object GetEffectiveValue() |
|||
{ |
|||
if (this.localValue != PerspexProperty.UnsetValue) |
|||
{ |
|||
return this.localValue; |
|||
} |
|||
else |
|||
{ |
|||
foreach (StyleEntry style in Enumerable.Reverse(this.styles)) |
|||
{ |
|||
if (style.Active) |
|||
{ |
|||
return style.Value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return PerspexProperty.UnsetValue; |
|||
} |
|||
|
|||
public IDisposable Subscribe(IObserver<Tuple<object, object>> observer) |
|||
{ |
|||
Contract.Requires<NullReferenceException>(observer != null); |
|||
|
|||
this.observers.Add(observer); |
|||
|
|||
return Disposable.Create(() => this.observers.Remove(observer)); |
|||
} |
|||
|
|||
private void Push() |
|||
{ |
|||
object value = this.GetEffectiveValue(); |
|||
|
|||
if (!object.Equals(this.lastValue, value)) |
|||
{ |
|||
foreach (IObserver<Tuple<object, object>> observer in this.observers) |
|||
{ |
|||
observer.OnNext(Tuple.Create(this.lastValue, value)); |
|||
} |
|||
|
|||
this.lastValue = value; |
|||
} |
|||
} |
|||
|
|||
private class StyleEntry |
|||
{ |
|||
private IObservable<bool> activator; |
|||
|
|||
public StyleEntry(object value) |
|||
{ |
|||
this.Active = true; |
|||
this.Value = value; |
|||
} |
|||
|
|||
public StyleEntry( |
|||
IObservable<bool> activator, |
|||
object value, |
|||
Action activeChanged, |
|||
Action<StyleEntry> completed) |
|||
{ |
|||
Contract.Requires<NullReferenceException>(activator != null); |
|||
Contract.Requires<NullReferenceException>(activeChanged != null); |
|||
|
|||
this.activator = activator; |
|||
this.Value = value; |
|||
|
|||
this.activator.Subscribe(x => this.Active = x, () => completed(this)); |
|||
} |
|||
|
|||
public bool Active |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
public object Value |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue