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.
using System;
using System.Reactive;
using System.Reactive.Subjects;
namespace Perspex.Markup.Binding
{
public abstract class ExpressionNode : IObservable<ExpressionValue>
internal abstract class ExpressionNode : IObservable<ExpressionValue>
{
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)
{
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.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
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))
{
@ -45,7 +47,7 @@ namespace Perspex.Markup.Binding
result[i].Next = result[i + 1];
}
return result;
return result[0];
}
else
{

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

@ -15,6 +15,7 @@ namespace Perspex.Markup.Binding
public class ExpressionObserver : ObservableBase<ExpressionValue>
{
private int _count;
private ExpressionNode _node;
/// <summary>
/// Initializes a new instance of the <see cref="ExpressionObserver"/> class.
@ -24,7 +25,7 @@ namespace Perspex.Markup.Binding
public ExpressionObserver(object root, string expression)
{
Root = root;
Nodes = ExpressionNodeBuilder.Build(expression);
_node = ExpressionNodeBuilder.Build(expression);
}
/// <summary>
@ -37,22 +38,16 @@ namespace Perspex.Markup.Binding
/// </returns>
public bool SetValue(object value)
{
var last = Nodes.Last() as PropertyAccessorNode;
IncrementCount();
if (last != null)
try
{
try
{
IncrementCount();
return last.SetValue(value);
}
finally
{
DecrementCount();
}
return _node.SetValue(value);
}
finally
{
DecrementCount();
}
return false;
}
/// <summary>
@ -60,17 +55,12 @@ namespace Perspex.Markup.Binding
/// </summary>
public object Root { get; }
/// <summary>
/// Gets a list of nodes representing the parts of the expression.
/// </summary>
public IList<ExpressionNode> Nodes { get; }
/// <inheritdoc/>
protected override IDisposable SubscribeCore(IObserver<ExpressionValue> observer)
{
IncrementCount();
var subscription = Nodes[0].Subscribe(observer);
var subscription = _node.Subscribe(observer);
return Disposable.Create(() =>
{
@ -83,7 +73,7 @@ namespace Perspex.Markup.Binding
{
if (_count++ == 0)
{
Nodes[0].Target = Root;
_node.Target = Root;
}
}
@ -91,7 +81,7 @@ namespace Perspex.Markup.Binding
{
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
{
public class PropertyAccessorNode : ExpressionNode
internal class PropertyAccessorNode : ExpressionNode
{
private PropertyInfo _propertyInfo;
@ -16,19 +16,26 @@ namespace Perspex.Markup.Binding
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 true;
return Next.SetValue(value);
}
else
{
if (_propertyInfo != null)
{
_propertyInfo.SetValue(Target, value);
return true;
}
return false;
return false;
}
}
public string PropertyName { get; }
protected override void SubscribeAndUpdate(object target)
{
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.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.
// 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 Xunit;
@ -11,7 +12,7 @@ namespace Perspex.Markup.UnitTests.Binding
[Fact]
public void Should_Build_Single_Property()
{
var result = ExpressionNodeBuilder.Build("Foo");
var result = ToList(ExpressionNodeBuilder.Build("Foo"));
Assert.Equal(1, result.Count);
Assert.IsType<PropertyAccessorNode>(result[0]);
@ -20,10 +21,23 @@ namespace Perspex.Markup.UnitTests.Binding
[Fact]
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.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