Browse Source
Now, two way bindings work as expected and setting a local value on a property with a binding sets the value temporarily until the binding changes value.pull/58/head
10 changed files with 559 additions and 289 deletions
@ -0,0 +1,17 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="IPerspexPropertyBinding.cs" company="Steven Kirk">
|
|||
// Copyright 2015 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Diagnostics |
|||
{ |
|||
public interface IPerspexPropertyBinding |
|||
{ |
|||
string Description { get; } |
|||
|
|||
int Priority { get; } |
|||
|
|||
object Value { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexPropertyBinding.cs" company="Steven Kirk">
|
|||
// Copyright 2015 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Diagnostics |
|||
{ |
|||
internal class PerspexPropertyBinding : IPerspexPropertyBinding |
|||
{ |
|||
public string Description { get; set; } |
|||
|
|||
public int Priority { get; set; } |
|||
|
|||
public object Value { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,97 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PriorityValue.cs" company="Steven Kirk">
|
|||
// Copyright 2014 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex |
|||
{ |
|||
using Perspex.Diagnostics; |
|||
using System; |
|||
|
|||
/// <summary>
|
|||
/// A registered binding in a <see cref="PriorityValue"/>.
|
|||
/// </summary>
|
|||
internal class PriorityBindingEntry : IDisposable |
|||
{ |
|||
/// <summary>
|
|||
/// The binding subscription.
|
|||
/// </summary>
|
|||
private IDisposable subscription; |
|||
|
|||
public PriorityBindingEntry(int index) |
|||
{ |
|||
this.Index = index; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a description of the binding.
|
|||
/// </summary>
|
|||
public string Description |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
public int Index |
|||
{ |
|||
get; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The current value of the binding.
|
|||
/// </summary>
|
|||
public object Value |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Starts listening to the binding.
|
|||
/// </summary>
|
|||
/// <param name="binding">The binding.</param>
|
|||
/// <param name="changed">Called when the binding changes.</param>
|
|||
/// <param name="completed">Called when the binding completes.</param>
|
|||
public void Start( |
|||
IObservable<object> binding, |
|||
Action<PriorityBindingEntry> changed, |
|||
Action<PriorityBindingEntry> completed) |
|||
{ |
|||
Contract.Requires<ArgumentNullException>(binding != null); |
|||
Contract.Requires<ArgumentNullException>(changed != null); |
|||
Contract.Requires<ArgumentNullException>(completed != null); |
|||
|
|||
if (this.subscription != null) |
|||
{ |
|||
throw new Exception("PriorityValue.Entry.Start() called more than once."); |
|||
} |
|||
|
|||
this.Value = PerspexProperty.UnsetValue; |
|||
|
|||
if (binding is IDescription) |
|||
{ |
|||
this.Description = ((IDescription)binding).Description; |
|||
} |
|||
|
|||
this.subscription = binding.Subscribe( |
|||
value => |
|||
{ |
|||
this.Value = value; |
|||
changed(this); |
|||
}, |
|||
() => completed(this)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Ends the binding subscription.
|
|||
/// </summary>
|
|||
public void Dispose() |
|||
{ |
|||
if (this.subscription != null) |
|||
{ |
|||
this.subscription.Dispose(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,121 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PriorityValueTests.cs" company="Steven Kirk">
|
|||
// Copyright 2013 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reactive.Disposables; |
|||
|
|||
internal class PriorityLevel |
|||
{ |
|||
private Action<PriorityLevel> changed; |
|||
|
|||
private object directValue; |
|||
|
|||
private int nextIndex; |
|||
|
|||
public PriorityLevel( |
|||
int priority, |
|||
Action<PriorityLevel> changed) |
|||
{ |
|||
Contract.Requires<ArgumentNullException>(changed != null); |
|||
|
|||
this.changed = changed; |
|||
this.Priority = priority; |
|||
this.Value = this.directValue = PerspexProperty.UnsetValue; |
|||
this.ActiveBindingIndex = -1; |
|||
this.Bindings = new LinkedList<PriorityBindingEntry>(); |
|||
} |
|||
|
|||
public int Priority { get; } |
|||
|
|||
public object DirectValue |
|||
{ |
|||
get |
|||
{ |
|||
return this.directValue; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.Value = this.directValue = value; |
|||
this.changed(this); |
|||
} |
|||
} |
|||
|
|||
public object Value { get; private set; } |
|||
|
|||
public int ActiveBindingIndex { get; private set; } |
|||
|
|||
public LinkedList<PriorityBindingEntry> Bindings { get; } |
|||
|
|||
public IDisposable Add(IObservable<object> binding) |
|||
{ |
|||
Contract.Requires<ArgumentNullException>(binding != null); |
|||
|
|||
var entry = new PriorityBindingEntry(this.nextIndex++); |
|||
var node = this.Bindings.AddFirst(entry); |
|||
|
|||
entry.Start(binding, this.Changed, this.Completed); |
|||
|
|||
return Disposable.Create(() => |
|||
{ |
|||
this.Bindings.Remove(node); |
|||
|
|||
if (entry.Index >= this.ActiveBindingIndex) |
|||
{ |
|||
this.ActivateFirstBinding(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private void Changed(PriorityBindingEntry entry) |
|||
{ |
|||
if (entry.Index >= this.ActiveBindingIndex) |
|||
{ |
|||
if (entry.Value != PerspexProperty.UnsetValue) |
|||
{ |
|||
this.Value = entry.Value; |
|||
this.ActiveBindingIndex = entry.Index; |
|||
this.changed(this); |
|||
} |
|||
else |
|||
{ |
|||
this.ActivateFirstBinding(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void Completed(PriorityBindingEntry entry) |
|||
{ |
|||
this.Bindings.Remove(entry); |
|||
|
|||
if (entry.Index >= this.ActiveBindingIndex) |
|||
{ |
|||
this.ActivateFirstBinding(); |
|||
} |
|||
} |
|||
|
|||
private void ActivateFirstBinding() |
|||
{ |
|||
foreach (var binding in this.Bindings) |
|||
{ |
|||
if (binding.Value != PerspexProperty.UnsetValue) |
|||
{ |
|||
this.Value = binding.Value; |
|||
this.ActiveBindingIndex = binding.Index; |
|||
this.changed(this); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
this.Value = this.DirectValue; |
|||
this.ActiveBindingIndex = -1; |
|||
this.changed(this); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue