Browse Source

Pass SetValue through expression chain.

pull/237/head
Steven Kirk 11 years ago
parent
commit
962c1ea01b
  1. 8
      src/Markup/Perspex.Markup/Binding/ExpressionNode.cs
  2. 12
      src/Markup/Perspex.Markup/Binding/ExpressionNodeBuilder.cs
  3. 34
      src/Markup/Perspex.Markup/Binding/ExpressionObserver.cs
  4. 23
      src/Markup/Perspex.Markup/Binding/PropertyAccessorNode.cs
  5. 2
      src/Markup/Perspex.Markup/Properties/AssemblyInfo.cs
  6. 18
      tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests.cs

8
src/Markup/Perspex.Markup/Binding/ExpressionNode.cs

@ -2,12 +2,11 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Reactive;
using System.Reactive.Subjects; using System.Reactive.Subjects;
namespace Perspex.Markup.Binding namespace Perspex.Markup.Binding
{ {
public abstract class ExpressionNode : IObservable<ExpressionValue> internal abstract class ExpressionNode : IObservable<ExpressionValue>
{ {
private object _target; private object _target;
@ -72,6 +71,11 @@ namespace Perspex.Markup.Binding
} }
} }
public virtual bool SetValue(object value)
{
return Next?.SetValue(value) ?? false;
}
public IDisposable Subscribe(IObserver<ExpressionValue> observer) public IDisposable Subscribe(IObserver<ExpressionValue> observer)
{ {
if (Next != null) if (Next != null)

12
src/Markup/Perspex.Markup/Binding/ExpressionNodeBuilder.cs

@ -1,16 +1,18 @@
using System; // Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Perspex.Markup.Binding namespace Perspex.Markup.Binding
{ {
public class ExpressionNodeBuilder internal class ExpressionNodeBuilder
{ {
public static IList<ExpressionNode> Build(string expression) public static ExpressionNode Build(string expression)
{ {
if (string.IsNullOrWhiteSpace(expression)) if (string.IsNullOrWhiteSpace(expression))
{ {
@ -45,7 +47,7 @@ namespace Perspex.Markup.Binding
result[i].Next = result[i + 1]; result[i].Next = result[i + 1];
} }
return result; return result[0];
} }
else else
{ {

34
src/Markup/Perspex.Markup/Binding/ExpressionObserver.cs

@ -15,6 +15,7 @@ namespace Perspex.Markup.Binding
public class ExpressionObserver : ObservableBase<ExpressionValue> public class ExpressionObserver : ObservableBase<ExpressionValue>
{ {
private int _count; private int _count;
private ExpressionNode _node;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ExpressionObserver"/> class. /// Initializes a new instance of the <see cref="ExpressionObserver"/> class.
@ -24,7 +25,7 @@ namespace Perspex.Markup.Binding
public ExpressionObserver(object root, string expression) public ExpressionObserver(object root, string expression)
{ {
Root = root; Root = root;
Nodes = ExpressionNodeBuilder.Build(expression); _node = ExpressionNodeBuilder.Build(expression);
} }
/// <summary> /// <summary>
@ -37,22 +38,16 @@ namespace Perspex.Markup.Binding
/// </returns> /// </returns>
public bool SetValue(object value) public bool SetValue(object value)
{ {
var last = Nodes.Last() as PropertyAccessorNode; IncrementCount();
if (last != null) try
{ {
try return _node.SetValue(value);
{ }
IncrementCount(); finally
return last.SetValue(value); {
} DecrementCount();
finally
{
DecrementCount();
}
} }
return false;
} }
/// <summary> /// <summary>
@ -60,17 +55,12 @@ namespace Perspex.Markup.Binding
/// </summary> /// </summary>
public object Root { get; } public object Root { get; }
/// <summary>
/// Gets a list of nodes representing the parts of the expression.
/// </summary>
public IList<ExpressionNode> Nodes { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override IDisposable SubscribeCore(IObserver<ExpressionValue> observer) protected override IDisposable SubscribeCore(IObserver<ExpressionValue> observer)
{ {
IncrementCount(); IncrementCount();
var subscription = Nodes[0].Subscribe(observer); var subscription = _node.Subscribe(observer);
return Disposable.Create(() => return Disposable.Create(() =>
{ {
@ -83,7 +73,7 @@ namespace Perspex.Markup.Binding
{ {
if (_count++ == 0) if (_count++ == 0)
{ {
Nodes[0].Target = Root; _node.Target = Root;
} }
} }
@ -91,7 +81,7 @@ namespace Perspex.Markup.Binding
{ {
if (--_count == 0) if (--_count == 0)
{ {
Nodes[0].Target = null; _node.Target = null;
} }
} }
} }

23
src/Markup/Perspex.Markup/Binding/PropertyAccessorNode.cs

@ -7,7 +7,7 @@ using System.Reflection;
namespace Perspex.Markup.Binding namespace Perspex.Markup.Binding
{ {
public class PropertyAccessorNode : ExpressionNode internal class PropertyAccessorNode : ExpressionNode
{ {
private PropertyInfo _propertyInfo; private PropertyInfo _propertyInfo;
@ -16,19 +16,26 @@ namespace Perspex.Markup.Binding
PropertyName = propertyName; PropertyName = propertyName;
} }
public bool SetValue(object value) public string PropertyName { get; }
public override bool SetValue(object value)
{ {
if (_propertyInfo != null) if (Next != null)
{ {
_propertyInfo.SetValue(Target, value); return Next.SetValue(value);
return true;
} }
else
{
if (_propertyInfo != null)
{
_propertyInfo.SetValue(Target, value);
return true;
}
return false; return false;
}
} }
public string PropertyName { get; }
protected override void SubscribeAndUpdate(object target) protected override void SubscribeAndUpdate(object target)
{ {
var result = ExpressionValue.None; var result = ExpressionValue.None;

2
src/Markup/Perspex.Markup/Properties/AssemblyInfo.cs

@ -28,3 +28,5 @@ using System.Runtime.InteropServices;
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("Perspex.Markup.UnitTests")]

18
tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests.cs

@ -1,6 +1,7 @@
// Copyright (c) The Perspex Project. All rights reserved. // Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections.Generic;
using Perspex.Markup.Binding; using Perspex.Markup.Binding;
using Xunit; using Xunit;
@ -11,7 +12,7 @@ namespace Perspex.Markup.UnitTests.Binding
[Fact] [Fact]
public void Should_Build_Single_Property() public void Should_Build_Single_Property()
{ {
var result = ExpressionNodeBuilder.Build("Foo"); var result = ToList(ExpressionNodeBuilder.Build("Foo"));
Assert.Equal(1, result.Count); Assert.Equal(1, result.Count);
Assert.IsType<PropertyAccessorNode>(result[0]); Assert.IsType<PropertyAccessorNode>(result[0]);
@ -20,10 +21,23 @@ namespace Perspex.Markup.UnitTests.Binding
[Fact] [Fact]
public void Should_Build_Property_Chain() public void Should_Build_Property_Chain()
{ {
var result = ExpressionNodeBuilder.Build("Foo.Bar.Baz"); var result = ToList(ExpressionNodeBuilder.Build("Foo.Bar.Baz"));
Assert.Equal(3, result.Count); Assert.Equal(3, result.Count);
Assert.IsType<PropertyAccessorNode>(result[0]); Assert.IsType<PropertyAccessorNode>(result[0]);
} }
private List<ExpressionNode> ToList(ExpressionNode node)
{
var result = new List<ExpressionNode>();
while (node != null)
{
result.Add(node);
node = node.Next;
}
return result;
}
} }
} }

Loading…
Cancel
Save