diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs
index 086257f24c..649596a74e 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs
@@ -115,6 +115,10 @@ namespace Avalonia.Markup.Xaml.Data
anchor,
enableDataValidation);
}
+ else if (RelativeSource.Mode == RelativeSourceMode.Self)
+ {
+ observer = CreateSourceObserver(target, pathInfo.Path, enableDataValidation);
+ }
else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent)
{
observer = CreateTemplatedParentObserver(target, pathInfo.Path);
diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs b/src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs
index 6771aaf644..c0eb581af2 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs
@@ -5,6 +5,7 @@ namespace Avalonia.Markup.Xaml.Data
{
public enum RelativeSourceMode
{
+ Self,
DataContext,
TemplatedParent,
}
diff --git a/src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs b/src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs
index dab5756976..51afe1ffbf 100644
--- a/src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs
+++ b/src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs
@@ -26,7 +26,7 @@ namespace Avalonia.Markup.Data
_nodes = null;
}
- public bool HasNodes => _nodes.Count > 0;
+ public bool HasNodes => _nodes?.Count > 0;
public void AddNode(string node) => _nodes.Add(node);
public void Commit(string expression)
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj
index 4ad740bab0..f820f7d5ab 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj
@@ -96,6 +96,7 @@
+
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Self.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Self.cs
new file mode 100644
index 0000000000..e0d16a9563
--- /dev/null
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Self.cs
@@ -0,0 +1,63 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using Moq;
+using Avalonia.Controls;
+using Avalonia.Data;
+using Avalonia.Markup.Xaml.Data;
+using Avalonia.Styling;
+using Xunit;
+using System.Reactive.Disposables;
+
+namespace Avalonia.Markup.Xaml.UnitTests.Data
+{
+ public class BindingTests_Self
+ {
+ [Fact]
+ public void Binding_To_Property_On_Self_Should_Work()
+ {
+ var target = new TextBlock
+ {
+ Tag = "Hello World!",
+ [!TextBlock.TextProperty] = new Binding("Tag")
+ {
+ RelativeSource = new RelativeSource(RelativeSourceMode.Self)
+ },
+ };
+
+ Assert.Equal("Hello World!", target.Text);
+ }
+
+ [Fact]
+ public void TwoWay_Binding_To_Property_On_Self_Should_Work()
+ {
+ var target = new TextBlock
+ {
+ Tag = "Hello World!",
+ [!TextBlock.TextProperty] = new Binding("Tag", BindingMode.TwoWay)
+ {
+ RelativeSource = new RelativeSource(RelativeSourceMode.Self)
+ },
+ };
+
+ Assert.Equal("Hello World!", target.Text);
+ target.Text = "Goodbye cruel world :(";
+ Assert.Equal("Goodbye cruel world :(", target.Text);
+ }
+
+ private Mock CreateTarget(
+ ITemplatedControl templatedParent = null,
+ string text = null)
+ {
+ var result = new Mock();
+
+ result.Setup(x => x.GetValue(Control.TemplatedParentProperty)).Returns(templatedParent);
+ result.Setup(x => x.GetValue((AvaloniaProperty)Control.TemplatedParentProperty)).Returns(templatedParent);
+ result.Setup(x => x.GetValue((AvaloniaProperty)TextBox.TextProperty)).Returns(text);
+ result.Setup(x => x.Bind(It.IsAny(), It.IsAny>(), It.IsAny()))
+ .Returns(Disposable.Empty);
+ return result;
+ }
+ }
+}
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs
index 868471466a..a66d6ac6d8 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs
@@ -145,5 +145,49 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
Assert.Equal("foo", border.DataContext);
}
}
+
+ [Fact(Skip = "OmniXaml doesn't support nested markup extensions. #119")]
+ public void Binding_To_Self_Works()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var loader = new AvaloniaXamlLoader();
+ var window = (Window)loader.Load(xaml);
+ var textBlock = (TextBlock)window.Content;
+
+ window.ApplyTemplate();
+
+ Assert.Equal("foo", textBlock.Text);
+ }
+ }
+
+ [Fact]
+ public void Longform_Binding_To_Self_Works()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+
+
+
+
+";
+ var loader = new AvaloniaXamlLoader();
+ var window = (Window)loader.Load(xaml);
+ var textBlock = (TextBlock)window.Content;
+
+ window.ApplyTemplate();
+
+ Assert.Equal("foo", textBlock.Text);
+ }
+ }
}
}