Browse Source

Got basic XAML control templates working.

pull/297/head
Steven Kirk 11 years ago
parent
commit
dab821249e
  1. 7
      samples/XamlTestApplicationPcl/XamlTestApp.paml
  2. 5
      src/Markup/Perspex.Markup.Xaml/Binding/XamlBindingDefinition.cs
  3. 54
      src/Markup/Perspex.Markup.Xaml/Binding/XamlTemplateBinding.cs
  4. 23
      src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs
  5. 28
      src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs
  6. 2
      src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
  7. 36
      src/Perspex.Base/PerspexObjectExtensions.cs

7
samples/XamlTestApplicationPcl/XamlTestApp.paml

@ -11,8 +11,11 @@
<Setter Property="Button.VerticalContentAlignment" Value="Center"/> <Setter Property="Button.VerticalContentAlignment" Value="Center"/>
<Setter Property="Button.Template"> <Setter Property="Button.Template">
<ControlTemplate TargetType="Button"> <ControlTemplate TargetType="Button">
<Border Padding="3"> <Border Padding="3"
<ContentPresenter Content="Content Here"/> Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>

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

@ -9,13 +9,16 @@ namespace Perspex.Markup.Xaml.Binding
{ {
public XamlBindingDefinition( public XamlBindingDefinition(
string sourcePropertyPath, string sourcePropertyPath,
BindingMode bindingMode) BindingMode bindingMode,
bool isTemplateBinding = false)
{ {
SourcePropertyPath = sourcePropertyPath; SourcePropertyPath = sourcePropertyPath;
BindingMode = bindingMode; BindingMode = bindingMode;
IsTemplateBinding = isTemplateBinding;
} }
public string SourcePropertyPath { get; } public string SourcePropertyPath { get; }
public BindingMode BindingMode { get; } public BindingMode BindingMode { get; }
public bool IsTemplateBinding { get; }
} }
} }

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

@ -0,0 +1,54 @@
// 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 = templatedParent.FindRegistered(SourcePropertyPath);
if (sourceProperty == null)
{
throw new InvalidOperationException(
$"The property {SourcePropertyPath} could not be found on {instance.GetType()}.");
}
instance.Bind(targetProperty, templatedParent.GetObservable(sourceProperty), BindingPriority.Style);
}
}
}

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

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

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

@ -0,0 +1,28 @@
// 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 OmniXaml;
using Perspex.Markup.Xaml.Binding;
namespace Perspex.Markup.Xaml.MarkupExtensions
{
public class TemplateBindingExtension : MarkupExtension
{
public TemplateBindingExtension()
{
}
public TemplateBindingExtension(string path)
{
Path = path;
}
public override object ProvideValue(MarkupExtensionContext extensionContext)
{
return new XamlBindingDefinition(Path, Mode, true);
}
public string Path { get; set; }
public BindingMode Mode { get; set; }
}
}

2
src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj

@ -40,6 +40,7 @@
</Compile> </Compile>
<Compile Include="Binding\SourceBindingEndpoint.cs" /> <Compile Include="Binding\SourceBindingEndpoint.cs" />
<Compile Include="Binding\TargetBindingEndpoint.cs" /> <Compile Include="Binding\TargetBindingEndpoint.cs" />
<Compile Include="Binding\XamlTemplateBinding.cs" />
<Compile Include="Binding\XamlBinding.cs" /> <Compile Include="Binding\XamlBinding.cs" />
<Compile Include="Binding\XamlBindingDefinition.cs" /> <Compile Include="Binding\XamlBindingDefinition.cs" />
<Compile Include="Context\PerspexAttachableXamlMember.cs" /> <Compile Include="Context\PerspexAttachableXamlMember.cs" />
@ -55,6 +56,7 @@
<Compile Include="Converters\SelectorTypeConverter.cs" /> <Compile Include="Converters\SelectorTypeConverter.cs" />
<Compile Include="Context\PerspexWiringContext.cs" /> <Compile Include="Context\PerspexWiringContext.cs" />
<Compile Include="Converters\TimeSpanTypeConverter.cs" /> <Compile Include="Converters\TimeSpanTypeConverter.cs" />
<Compile Include="MarkupExtensions\TemplateBindingExtension.cs" />
<Compile Include="MarkupExtensions\BindingExtension.cs" /> <Compile Include="MarkupExtensions\BindingExtension.cs" />
<Compile Include="Converters\BrushTypeConverter.cs" /> <Compile Include="Converters\BrushTypeConverter.cs" />
<Compile Include="Converters\BitmapTypeConverter.cs" /> <Compile Include="Converters\BitmapTypeConverter.cs" />

36
src/Perspex.Base/PerspexObjectExtensions.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
namespace Perspex namespace Perspex
@ -51,6 +52,41 @@ namespace Perspex
return observable.Subscribe(e => SubscribeAdapter(e, handler)); return observable.Subscribe(e => SubscribeAdapter(e, handler));
} }
/// <summary>
/// Finds a registered property on a <see cref="PerspexObject"/> by name.
/// </summary>
/// <param name="o">The object.</param>
/// <param name="name">
/// The property name. If an attached property it should be in the form
/// "OwnerType.PropertyName".
/// </param>
/// <returns>
/// The registered property or null if no matching property found.
/// </returns>
public static PerspexProperty FindRegistered(this PerspexObject o, string name)
{
Contract.Requires<ArgumentNullException>(o != null);
Contract.Requires<ArgumentNullException>(name != null);
var parts = name.Split('.');
if (parts.Length < 1 || parts.Length > 2)
{
throw new ArgumentException("Invalid property name.");
}
if (parts.Length == 1)
{
return o.GetRegisteredProperties()
.FirstOrDefault(x => !x.IsAttached && x.Name == parts[0]);
}
else
{
return o.GetRegisteredProperties()
.FirstOrDefault(x => x.IsAttached && x.OwnerType.Name == parts[0] && x.Name == parts[1]);
}
}
/// <summary> /// <summary>
/// Observer method for <see cref="AddClassHandler{TTarget}(IObservable{PerspexPropertyChangedEventArgs}, /// Observer method for <see cref="AddClassHandler{TTarget}(IObservable{PerspexPropertyChangedEventArgs},
/// Func{TTarget, Action{PerspexPropertyChangedEventArgs}})"/>. /// Func{TTarget, Action{PerspexPropertyChangedEventArgs}})"/>.

Loading…
Cancel
Save