From f5d5d2aebe7f78e37d769f2206618f50d1133f4e Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 3 Feb 2016 12:03:33 +0100 Subject: [PATCH] Add support for Source in binding. Closes #318. --- .../Perspex.Markup.Xaml/Data/Binding.cs | 50 +++++++++++-------- .../MarkupExtensions/BindingExtension.cs | 1 + .../Data/BindingTests_Source.cs | 39 +++++++++++++++ .../Perspex.Markup.Xaml.UnitTests.csproj | 1 + 4 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_Source.cs diff --git a/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs b/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs index 8a254cbf6e..c01a8c29f2 100644 --- a/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs +++ b/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs @@ -36,6 +36,11 @@ namespace Perspex.Markup.Xaml.Data /// public BindingMode Mode { get; set; } + /// + /// Gets or sets the binding path. + /// + public string Path { get; set; } + /// /// Gets or sets the binding priority. /// @@ -47,9 +52,9 @@ namespace Perspex.Markup.Xaml.Data public RelativeSource RelativeSource { get; set; } /// - /// Gets or sets the binding path. + /// Gets or sets the source for the binding. /// - public string Path { get; set; } + public object Source { get; set; } /// /// 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(target != null); + + var result = new ExpressionObserver( + ControlLocator.Track(target, elementName), + path); + return result; + } + + private ExpressionObserver CreateSourceObserver(object source, string path) + { + Contract.Requires(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(target != null); - - var result = new ExpressionObserver( - ControlLocator.Track(target, elementName), - path); - return result; - } - private IControl LookupNamedControl(IControl target) { Contract.Requires(target != null); diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs index d8a668da08..20efff1e81 100644 --- a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs +++ b/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; } } } \ No newline at end of file diff --git a/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_Source.cs b/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_Source.cs new file mode 100644 index 0000000000..6636dc08ab --- /dev/null +++ b/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); } + } + } + } +} diff --git a/tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj b/tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj index 8a79e9eb28..4859e65e5e 100644 --- a/tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj +++ b/tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj @@ -85,6 +85,7 @@ +