Browse Source

Merged XamlBinding and XamlTemplateBinding.

pull/297/head
Steven Kirk 11 years ago
parent
commit
785238bdf1
  1. 25
      src/Markup/Perspex.Markup.Xaml/Binding/RelativeSource.cs
  2. 42
      src/Markup/Perspex.Markup.Xaml/Binding/XamlBinding.cs
  3. 19
      src/Markup/Perspex.Markup.Xaml/Binding/XamlBindingDefinition.cs
  4. 57
      src/Markup/Perspex.Markup.Xaml/Binding/XamlTemplateBinding.cs
  5. 25
      src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs
  6. 6
      src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs
  7. 8
      src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs
  8. 1
      src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
  9. 4
      tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs
  10. 8
      tests/Perspex.Markup.Xaml.UnitTests/Binding/XamlBindingTests.cs
  11. 4
      tests/Perspex.Markup.Xaml.UnitTests/XamlBindingTest.cs

25
src/Markup/Perspex.Markup.Xaml/Binding/RelativeSource.cs

@ -0,0 +1,25 @@
// 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.
namespace Perspex.Markup.Xaml.Binding
{
public enum RelativeSourceMode
{
DataContext,
TemplatedParent,
}
public class RelativeSource
{
public RelativeSource()
{
}
public RelativeSource(RelativeSourceMode mode)
{
Mode = mode;
}
public RelativeSourceMode Mode { get; set; }
}
}

42
src/Markup/Perspex.Markup.Xaml/Binding/XamlBinding.cs

@ -23,10 +23,11 @@ namespace Perspex.Markup.Xaml.Binding
_typeConverterProvider = typeConverterProvider;
}
public BindingMode Mode { get; set; }
public BindingPriority Priority { get; set; }
public RelativeSource RelativeSource { get; set; }
public string SourcePropertyPath { get; set; }
public BindingMode BindingMode { get; set; }
public void Bind(IObservablePropertyBag instance, PerspexProperty property)
{
var subject = new ExpressionSubject(
@ -35,7 +36,18 @@ namespace Perspex.Markup.Xaml.Binding
if (subject != null)
{
Bind(instance, property, subject);
if (RelativeSource?.Mode != RelativeSourceMode.TemplatedParent)
{
Bind(instance, property, subject);
}
else
{
instance.GetObservable(Control.TemplatedParentProperty)
.Where(x => x != null)
.OfType<PerspexObject>()
.Take(1)
.Subscribe(x => BindToTemplatedParent((PerspexObject)instance, property, x));
}
}
}
@ -62,8 +74,8 @@ namespace Perspex.Markup.Xaml.Binding
internal void Bind(IObservablePropertyBag target, PerspexProperty property, ISubject<object> subject)
{
var mode = BindingMode == BindingMode.Default ?
property.DefaultBindingMode : BindingMode;
var mode = Mode == BindingMode.Default ?
property.DefaultBindingMode : Mode;
switch (mode)
{
@ -85,5 +97,25 @@ namespace Perspex.Markup.Xaml.Binding
break;
}
}
private void BindToTemplatedParent(
PerspexObject instance,
PerspexProperty targetProperty,
PerspexObject templatedParent)
{
var sourceProperty = PerspexPropertyRegistry.Instance.FindRegistered(
templatedParent,
SourcePropertyPath);
if (sourceProperty == null)
{
throw new InvalidOperationException(
$"The property {SourcePropertyPath} could not be found on {templatedParent.GetType()}.");
}
instance.Bind(targetProperty, templatedParent.GetObservable(sourceProperty), BindingPriority.Style);
templatedParent.Bind(sourceProperty, instance.GetObservable(targetProperty), BindingPriority.Style);
}
}
}

19
src/Markup/Perspex.Markup.Xaml/Binding/XamlBindingDefinition.cs

@ -1,24 +1,13 @@
// 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 Perspex.Controls;
namespace Perspex.Markup.Xaml.Binding
{
public class XamlBindingDefinition
{
public XamlBindingDefinition(
string sourcePropertyPath,
BindingMode bindingMode,
bool isTemplateBinding = false)
{
SourcePropertyPath = sourcePropertyPath;
BindingMode = bindingMode;
IsTemplateBinding = isTemplateBinding;
}
public string SourcePropertyPath { get; }
public BindingMode BindingMode { get; }
public bool IsTemplateBinding { get; }
public BindingMode Mode { get; set; }
public BindingPriority Priority { get; set; }
public RelativeSource RelativeSource { get; set; }
public string SourcePropertyPath { get; set; }
}
}

57
src/Markup/Perspex.Markup.Xaml/Binding/XamlTemplateBinding.cs

@ -1,57 +0,0 @@
// 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 System;
using System.Reactive.Linq;
using OmniXaml.TypeConversion;
using Perspex.Controls;
using Perspex.Styling;
namespace Perspex.Markup.Xaml.Binding
{
public class XamlTemplateBinding
{
private readonly ITypeConverterProvider _typeConverterProvider;
public XamlTemplateBinding()
{
}
public XamlTemplateBinding(ITypeConverterProvider typeConverterProvider)
{
_typeConverterProvider = typeConverterProvider;
}
public string SourcePropertyPath { get; set; }
public BindingMode BindingMode { get; set; }
public void Bind(PerspexObject instance, PerspexProperty targetProperty)
{
instance.GetObservable(Control.TemplatedParentProperty)
.Where(x => x != null)
.OfType<PerspexObject>()
.Take(1)
.Subscribe(x => BindToTemplatedParent(instance, targetProperty, x));
}
private void BindToTemplatedParent(
PerspexObject instance,
PerspexProperty targetProperty,
PerspexObject templatedParent)
{
var sourceProperty = PerspexPropertyRegistry.Instance.FindRegistered(
templatedParent,
SourcePropertyPath);
if (sourceProperty == null)
{
throw new InvalidOperationException(
$"The property {SourcePropertyPath} could not be found on {templatedParent.GetType()}.");
}
instance.Bind(targetProperty, templatedParent.GetObservable(sourceProperty), BindingPriority.Style);
templatedParent.Bind(sourceProperty, instance.GetObservable(targetProperty), BindingPriority.Style);
}
}
}

25
src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs

@ -109,26 +109,15 @@ namespace Perspex.Markup.Xaml.Context
$"Cannot find '{propertyName}' on '{instance.GetType()}");
}
if (!def.IsTemplateBinding)
var binding = new XamlBinding
{
var binding = new XamlBinding
{
BindingMode = def.BindingMode,
SourcePropertyPath = def.SourcePropertyPath,
};
Mode = def.Mode,
Priority = def.Priority,
RelativeSource = def.RelativeSource,
SourcePropertyPath = def.SourcePropertyPath,
};
binding.Bind(perspexObject, property);
}
else
{
var binding = new XamlTemplateBinding
{
BindingMode = def.BindingMode,
SourcePropertyPath = def.SourcePropertyPath,
};
binding.Bind(perspexObject, property);
}
binding.Bind(perspexObject, property);
}
}

6
src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs

@ -21,7 +21,11 @@ namespace Perspex.Markup.Xaml.MarkupExtensions
public override object ProvideValue(MarkupExtensionContext extensionContext)
{
return new XamlBindingDefinition(Path, Mode);
return new XamlBindingDefinition
{
Mode = Mode,
SourcePropertyPath = Path,
};
}
public string Path { get; set; }

8
src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs

@ -19,7 +19,13 @@ namespace Perspex.Markup.Xaml.MarkupExtensions
public override object ProvideValue(MarkupExtensionContext extensionContext)
{
return new XamlBindingDefinition(Path, Mode, true);
return new XamlBindingDefinition
{
Mode = Mode,
Priority = BindingPriority.TemplatedParent,
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
SourcePropertyPath = Path,
};
}
public string Path { get; set; }

1
src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj

@ -38,6 +38,7 @@
<Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Binding\RelativeSource.cs" />
<Compile Include="Binding\SourceBindingEndpoint.cs" />
<Compile Include="Binding\TargetBindingEndpoint.cs" />
<Compile Include="Binding\XamlTemplateBinding.cs" />

4
tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs

@ -404,13 +404,13 @@ namespace Perspex.Controls.UnitTests.Primitives
var itemsBinding = new XamlBinding
{
SourcePropertyPath = "Items",
BindingMode = BindingMode.OneWay,
Mode = BindingMode.OneWay,
};
var selectedItemsBinding = new XamlBinding
{
SourcePropertyPath = "SelectedItems",
BindingMode = BindingMode.OneWay,
Mode = BindingMode.OneWay,
};
// Bind Items and SelectedItems to the VM.

8
tests/Perspex.Markup.Xaml.UnitTests/Binding/XamlBindingTests.cs

@ -20,7 +20,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Binding
var binding = new XamlBinding
{
SourcePropertyPath = "Foo",
BindingMode = BindingMode.OneWay,
Mode = BindingMode.OneWay,
};
binding.Bind(target.Object, TextBox.TextProperty);
@ -38,7 +38,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Binding
var binding = new XamlBinding
{
SourcePropertyPath = "Foo",
BindingMode = BindingMode.TwoWay,
Mode = BindingMode.TwoWay,
};
binding.Bind(target.Object, TextBox.TextProperty);
@ -58,7 +58,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Binding
var binding = new XamlBinding
{
SourcePropertyPath = "Foo",
BindingMode = BindingMode.OneTime,
Mode = BindingMode.OneTime,
};
binding.Bind(target.Object, TextBox.TextProperty, expression);
@ -87,7 +87,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Binding
var binding = new XamlBinding
{
SourcePropertyPath = "Foo",
BindingMode = BindingMode.OneWayToSource,
Mode = BindingMode.OneWayToSource,
};
binding.Bind(target.Object, TextBox.TextProperty, expression.Object);

4
tests/Perspex.Markup.Xaml.UnitTests/XamlBindingTest.cs

@ -31,13 +31,13 @@ namespace Perspex.Xaml.Base.UnitTest
var fooBinding = new XamlBinding
{
SourcePropertyPath = "Foo",
BindingMode = BindingMode.TwoWay,
Mode = BindingMode.TwoWay,
};
var barBinding = new XamlBinding
{
SourcePropertyPath = "Bar",
BindingMode = BindingMode.TwoWay,
Mode = BindingMode.TwoWay,
};
// Bind Foo and Bar to the VM.

Loading…
Cancel
Save