Browse Source

Pass SetValue through expression chain.

Steven Kirk 10 years ago
parent
commit
962c1ea01b

+ 6 - 2
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)

+ 7 - 5
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
             {

+ 12 - 22
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;
             }
         }
     }

+ 15 - 8
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 - 0
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")]

+ 16 - 2
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;
+        }
     }
 }