diff --git a/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs b/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs
index 596ad401df..56bfe07b3c 100644
--- a/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs
+++ b/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs
@@ -42,7 +42,7 @@ namespace Perspex.Markup.Xaml.Data
///
/// Gets or sets the binding path.
///
- public string SourcePropertyPath { get; set; }
+ public string Path { get; set; }
///
/// Applies the binding to a property on an instance.
@@ -82,19 +82,30 @@ namespace Perspex.Markup.Xaml.Data
Contract.Requires(target != null);
Contract.Requires(targetType != null);
+ var pathInfo = ParsePath(Path);
+ ValidateState(pathInfo);
+
ExpressionObserver observer;
- if (ElementName != null)
+ if (pathInfo.ElementName != null || ElementName != null)
{
- observer = CreateElementSubject((IControl)target);
+ observer = CreateElementSubject(
+ (IControl)target,
+ pathInfo.ElementName ?? ElementName,
+ pathInfo.Path);
}
else if (RelativeSource == null || RelativeSource.Mode == RelativeSourceMode.DataContext)
{
- observer = CreateDataContextSubject(target, targetIsDataContext);
+ observer = CreateDataContextSubject(
+ target,
+ pathInfo.Path,
+ targetIsDataContext);
}
else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent)
{
- observer = CreateTemplatedParentSubject(target);
+ observer = CreateTemplatedParentSubject(
+ target,
+ pathInfo.Path);
}
else
{
@@ -143,8 +154,56 @@ namespace Perspex.Markup.Xaml.Data
}
}
+ private static PathInfo ParsePath(string path)
+ {
+ var result = new PathInfo();
+
+ if (string.IsNullOrWhiteSpace(path) || path == ".")
+ {
+ result.Path = path;
+ }
+ else if (path.StartsWith("#"))
+ {
+ var dot = path.IndexOf('.');
+
+ if (dot != -1)
+ {
+ result.Path = path.Substring(dot + 1);
+ result.ElementName = path.Substring(1, dot - 1);
+ }
+ else
+ {
+ result.Path = string.Empty;
+ result.ElementName = path.Substring(1);
+ }
+ }
+ else
+ {
+ result.Path = path;
+ }
+
+ return result;
+ }
+
+ private void ValidateState(PathInfo pathInfo)
+ {
+ if (pathInfo.ElementName != null && ElementName != null)
+ {
+ throw new InvalidOperationException(
+ "ElementName property cannot be set when an #elementName path is provided.");
+ }
+
+ if ((pathInfo.ElementName != null || ElementName != null) &&
+ RelativeSource != null)
+ {
+ throw new InvalidOperationException(
+ "ElementName property cannot be set with a RelativeSource.");
+ }
+ }
+
private ExpressionObserver CreateDataContextSubject(
IObservablePropertyBag target,
+ string path,
bool targetIsDataContext)
{
Contract.Requires(target != null);
@@ -156,7 +215,7 @@ namespace Perspex.Markup.Xaml.Data
{
var result = new ExpressionObserver(
() => dataContextHost.GetValue(Control.DataContextProperty),
- GetExpression());
+ path);
dataContextHost.GetObservable(Control.DataContextProperty).Subscribe(x =>
result.UpdateRoot());
return result;
@@ -168,13 +227,15 @@ namespace Perspex.Markup.Xaml.Data
}
}
- private ExpressionObserver CreateTemplatedParentSubject(IObservablePropertyBag target)
+ private ExpressionObserver CreateTemplatedParentSubject(
+ IObservablePropertyBag target,
+ string path)
{
Contract.Requires(target != null);
var result = new ExpressionObserver(
() => target.GetValue(Control.TemplatedParentProperty),
- GetExpression());
+ path);
if (target.GetValue(Control.TemplatedParentProperty) == null)
{
@@ -189,13 +250,16 @@ namespace Perspex.Markup.Xaml.Data
return result;
}
- private ExpressionObserver CreateElementSubject(IControl target)
+ private ExpressionObserver CreateElementSubject(
+ IControl target,
+ string elementName,
+ string path)
{
Contract.Requires(target != null);
var result = new ExpressionObserver(
- ControlLocator.Track(target, ElementName),
- GetExpression());
+ ControlLocator.Track(target, elementName),
+ path);
return result;
}
@@ -214,10 +278,10 @@ namespace Perspex.Markup.Xaml.Data
return nameScope.Find(ElementName);
}
- private string GetExpression()
+ private class PathInfo
{
- return SourcePropertyPath == null || SourcePropertyPath == "." ?
- string.Empty : SourcePropertyPath;
+ public string Path { get; set; }
+ public string ElementName { get; set; }
}
}
}
\ No newline at end of file
diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs
index 143a9f1f25..c2cdc5efd3 100644
--- a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs
+++ b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs
@@ -24,7 +24,7 @@ namespace Perspex.Markup.Xaml.MarkupExtensions
Converter = Converter,
ElementName = ElementName,
Mode = Mode,
- SourcePropertyPath = Path,
+ Path = Path,
};
}
diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs
index da20631177..b3bd1c7c75 100644
--- a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs
+++ b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs
@@ -26,7 +26,7 @@ namespace Perspex.Markup.Xaml.MarkupExtensions
Mode = Mode,
Priority = BindingPriority.TemplatedParent,
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
- SourcePropertyPath = Path,
+ Path = Path,
};
}
diff --git a/src/Markup/Perspex.Markup.Xaml/OmniXAML b/src/Markup/Perspex.Markup.Xaml/OmniXAML
index 55fc2abc71..85f2814e7a 160000
--- a/src/Markup/Perspex.Markup.Xaml/OmniXAML
+++ b/src/Markup/Perspex.Markup.Xaml/OmniXAML
@@ -1 +1 @@
-Subproject commit 55fc2abc715885d3686f8c8605f34714445cd72f
+Subproject commit 85f2814e7a0daa76d9b1e63b1a329cb291be30a9
diff --git a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
index cebb76826f..de0e4f9c82 100644
--- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
+++ b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
@@ -185,7 +185,6 @@
-
diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs b/src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs
index 6672727014..dc9143be1b 100644
--- a/src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs
+++ b/src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs
@@ -35,7 +35,7 @@ namespace Perspex.Markup.Xaml.Templates
{
if (ItemsSource != null)
{
- var obs = new ExpressionObserver(item, ItemsSource.SourcePropertyPath);
+ var obs = new ExpressionObserver(item, ItemsSource.Path);
return obs.Take(1).Wait() as IEnumerable;
}
diff --git a/src/Perspex.Themes.Default/TextBox.paml b/src/Perspex.Themes.Default/TextBox.paml
index 8ed353c1e5..db477a6313 100644
--- a/src/Perspex.Themes.Default/TextBox.paml
+++ b/src/Perspex.Themes.Default/TextBox.paml
@@ -22,9 +22,9 @@
+ Path="UseFloatingWatermark"/>
diff --git a/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs b/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs
index d348ab126c..d651216ca3 100644
--- a/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs
+++ b/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs
@@ -403,13 +403,13 @@ namespace Perspex.Controls.UnitTests.Primitives
var itemsBinding = new Binding
{
- SourcePropertyPath = "Items",
+ Path = "Items",
Mode = BindingMode.OneWay,
};
var selectedItemsBinding = new Binding
{
- SourcePropertyPath = "SelectedItems",
+ Path = "SelectedItems",
Mode = BindingMode.OneWay,
};
diff --git a/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests.cs b/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests.cs
index 2c4441d3a3..9184b485b7 100644
--- a/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests.cs
+++ b/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests.cs
@@ -20,7 +20,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var target = CreateTarget();
var binding = new Binding
{
- SourcePropertyPath = "Foo",
+ Path = "Foo",
Mode = BindingMode.OneWay,
};
@@ -38,7 +38,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var target = CreateTarget();
var binding = new Binding
{
- SourcePropertyPath = "Foo",
+ Path = "Foo",
Mode = BindingMode.TwoWay,
};
@@ -58,7 +58,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var target = CreateTarget(dataContext: dataContext);
var binding = new Binding
{
- SourcePropertyPath = "Foo",
+ Path = "Foo",
Mode = BindingMode.OneTime,
};
@@ -87,7 +87,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var target = CreateTarget(text: textObservable.Object);
var binding = new Binding
{
- SourcePropertyPath = "Foo",
+ Path = "Foo",
Mode = BindingMode.OneWayToSource,
};
@@ -102,7 +102,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var target = CreateTarget(null);
var binding = new Binding
{
- SourcePropertyPath = "Foo",
+ Path = "Foo",
};
binding.Bind(target.Object, TextBox.TextProperty);
@@ -127,7 +127,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var binding = new Binding
{
- SourcePropertyPath = "Header",
+ Path = "Header",
};
binding.Bind(parent.Child, Control.DataContextProperty);
@@ -145,7 +145,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var target = CreateTarget(null);
var binding = new Binding
{
- SourcePropertyPath = "Foo",
+ Path = "Foo",
};
var result = binding.CreateSubject(target.Object, TextBox.TextProperty.PropertyType);
@@ -161,7 +161,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var binding = new Binding
{
Converter = converter.Object,
- SourcePropertyPath = "Foo",
+ Path = "Foo",
};
var result = binding.CreateSubject(target.Object, TextBox.TextProperty.PropertyType);
@@ -189,13 +189,13 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var fooBinding = new Binding
{
- SourcePropertyPath = "Foo",
+ Path = "Foo",
Mode = BindingMode.TwoWay,
};
var barBinding = new Binding
{
- SourcePropertyPath = "Bar",
+ Path = "Bar",
Mode = BindingMode.TwoWay,
};
diff --git a/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs b/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs
index 3efd910c74..bde7297d47 100644
--- a/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs
+++ b/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs
@@ -35,7 +35,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var binding = new Binding
{
ElementName = "source",
- SourcePropertyPath = "Text",
+ Path = "Text",
};
binding.Bind(target, TextBlock.TextProperty);
@@ -66,7 +66,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var binding = new Binding
{
ElementName = "source",
- SourcePropertyPath = "Text",
+ Path = "Text",
};
binding.Bind(target, TextBlock.TextProperty);
diff --git a/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs b/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs
index 09d3aa461f..af0b492e49 100644
--- a/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs
+++ b/tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs
@@ -23,7 +23,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
Mode = BindingMode.OneWay,
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
Priority = BindingPriority.TemplatedParent,
- SourcePropertyPath = "Foo",
+ Path = "Foo",
};
binding.Bind(target.Object, TextBox.TextProperty);
@@ -43,7 +43,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
Mode = BindingMode.TwoWay,
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
Priority = BindingPriority.TemplatedParent,
- SourcePropertyPath = "Foo",
+ Path = "Foo",
};
binding.Bind(target.Object, TextBox.TextProperty);
@@ -62,7 +62,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
var target = CreateTarget(text: textObservable.Object);
var binding = new Binding
{
- SourcePropertyPath = "Foo",
+ Path = "Foo",
Mode = BindingMode.OneWayToSource,
};
diff --git a/tests/Perspex.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs b/tests/Perspex.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs
index 4a86be98f7..23db6d4c39 100644
--- a/tests/Perspex.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs
+++ b/tests/Perspex.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs
@@ -25,9 +25,9 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
Converter = new ConcatConverter(),
Bindings = new[]
{
- new Binding { SourcePropertyPath = "A" },
- new Binding { SourcePropertyPath = "B" },
- new Binding { SourcePropertyPath = "C" },
+ new Binding { Path = "A" },
+ new Binding { Path = "B" },
+ new Binding { Path = "C" },
}
};