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 @@
+