Browse Source

Add support for Source in binding.

Closes #318.
Steven Kirk 9 years ago
parent
commit
f5d5d2aebe

+ 30 - 20
src/Markup/Perspex.Markup.Xaml/Data/Binding.cs

@@ -36,6 +36,11 @@ namespace Perspex.Markup.Xaml.Data
         /// </summary>
         public BindingMode Mode { get; set; }
 
+        /// <summary>
+        /// Gets or sets the binding path.
+        /// </summary>
+        public string Path { get; set; }
+
         /// <summary>
         /// Gets or sets the binding priority.
         /// </summary>
@@ -47,9 +52,9 @@ namespace Perspex.Markup.Xaml.Data
         public RelativeSource RelativeSource { get; set; }
 
         /// <summary>
-        /// Gets or sets the binding path.
+        /// Gets or sets the source for the binding.
         /// </summary>
-        public string Path { get; set; }
+        public object Source { get; set; }
 
         /// <summary>
         /// Creates a subject that can be used to get and set the value of the binding.
@@ -67,7 +72,6 @@ namespace Perspex.Markup.Xaml.Data
             ValidateState(pathInfo);
 
             ExpressionObserver observer;
-            var targetIsDataContext = targetProperty == Control.DataContextProperty;
 
             if (pathInfo.ElementName != null || ElementName != null)
             {
@@ -76,18 +80,20 @@ namespace Perspex.Markup.Xaml.Data
                     pathInfo.ElementName ?? ElementName, 
                     pathInfo.Path);
             }
+            else if (Source != null)
+            {
+                observer = CreateSourceObserver(Source, pathInfo.Path);
+            }
             else if (RelativeSource == null || RelativeSource.Mode == RelativeSourceMode.DataContext)
             {
                 observer = CreateDataContexObserver(
                     target, 
                     pathInfo.Path,
-                    targetIsDataContext);
+                    targetProperty == Control.DataContextProperty);
             }
             else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent)
             {
-                observer = CreateTemplatedParentObserver(
-                    target,
-                    pathInfo.Path);
+                observer = CreateTemplatedParentObserver(target, pathInfo.Path);
             }
             else
             {
@@ -178,6 +184,23 @@ namespace Perspex.Markup.Xaml.Data
             }
         }
 
+        private ExpressionObserver CreateElementObserver(IControl target, string elementName, string path)
+        {
+            Contract.Requires<ArgumentNullException>(target != null);
+
+            var result = new ExpressionObserver(
+                ControlLocator.Track(target, elementName),
+                path);
+            return result;
+        }
+
+        private ExpressionObserver CreateSourceObserver(object source, string path)
+        {
+            Contract.Requires<ArgumentNullException>(source != null);
+
+            return new ExpressionObserver(source, path);
+        }
+
         private ExpressionObserver CreateTemplatedParentObserver(
             IPerspexObject target,
             string path)
@@ -196,19 +219,6 @@ namespace Perspex.Markup.Xaml.Data
             return result;
         }
 
-        private ExpressionObserver CreateElementObserver(
-            IControl target,
-            string elementName,
-            string path)
-        {
-            Contract.Requires<ArgumentNullException>(target != null);
-
-            var result = new ExpressionObserver(
-                ControlLocator.Track(target, elementName), 
-                path);
-            return result;
-        }
-
         private IControl LookupNamedControl(IControl target)
         {
             Contract.Requires<ArgumentNullException>(target != null);

+ 1 - 0
src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs

@@ -37,5 +37,6 @@ namespace Perspex.Markup.Xaml.MarkupExtensions
         public BindingMode Mode { get; set; }
         public string Path { get; set; }
         public BindingPriority Priority { get; set; } = BindingPriority.LocalValue;
+        public object Source { get; set; }
     }
 }

+ 39 - 0
tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_Source.cs

@@ -0,0 +1,39 @@
+// 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 Moq;
+using Perspex.Controls;
+using Perspex.Data;
+using Perspex.Markup.Data;
+using Perspex.Markup.Xaml.Data;
+using ReactiveUI;
+using Xunit;
+
+namespace Perspex.Markup.Xaml.UnitTests.Data
+{
+    public class BindingTests_Source
+    {
+        [Fact]
+        public void Source_Should_Be_Used()
+        {
+            var source = new Source { Foo = "foo" };
+            var binding = new Binding { Source = source, Path = "Foo" };
+            var target = new TextBlock();
+
+            target.Bind(TextBlock.TextProperty, binding);
+
+            Assert.Equal(target.Text, "foo");
+        }
+
+        public class Source : ReactiveObject
+        {
+            private string _foo;
+
+            public string Foo
+            {
+                get { return _foo; }
+                set { this.RaiseAndSetIfChanged(ref _foo, value); }
+            }
+        }
+    }
+}

+ 1 - 0
tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj

@@ -85,6 +85,7 @@
     <Otherwise />
   </Choose>
   <ItemGroup>
+    <Compile Include="Data\BindingTests_Source.cs" />
     <Compile Include="Data\BindingTests_ElementName.cs" />
     <Compile Include="Data\MultiBindingTests.cs" />
     <Compile Include="Data\BindingTests_TemplatedParent.cs" />