Browse Source

Handle attached properties in PerspexPropertyConverter.

pull/145/head
Steven Kirk 11 years ago
parent
commit
91dda4c2d0
  1. 63
      Tests/Perspex.Markup.Xaml.UnitTests/Converters/PerspexPropertyConverterTest.cs
  2. 1
      Tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj
  3. 25
      src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyConverter.cs
  4. 31
      src/Perspex.Base/PerspexObject.cs
  5. 8
      tests/Perspex.Base.UnitTests/PerspexObjectTests_Metadata.cs

63
Tests/Perspex.Markup.Xaml.UnitTests/Converters/PerspexPropertyConverterTest.cs

@ -0,0 +1,63 @@
// 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 OmniXaml;
using OmniXaml.TypeConversion;
using OmniXaml.Typing;
using Perspex.Markup.Xaml.Converters;
using Xunit;
namespace Perspex.Markup.Xaml.UnitTests.Converters
{
public class PerspexPropertyConverterTest
{
public PerspexPropertyConverterTest()
{
// Ensure properties are registered.
var foo = Class1.FooProperty;
var attached = AttachedOwner.AttachedProperty;
}
[Fact]
public void ConvertFrom_Finds_Fully_Qualified_Property()
{
var target = new PerspexPropertyConverter();
var context = CreateContext();
var result = target.ConvertFrom(context, null, "Class1.Foo");
}
[Fact]
public void ConvertFrom_Finds_Attached_Property()
{
var target = new PerspexPropertyConverter();
var context = CreateContext();
var result = target.ConvertFrom(context, null, "AttachedOwner.Attached");
}
private IXamlTypeConverterContext CreateContext()
{
var context = new Mock<IXamlTypeConverterContext>();
var typeRepository = new Mock<IXamlTypeRepository>();
var featureProvider = new Mock<ITypeFeatureProvider>();
var class1XamlType = new XamlType(typeof(Class1), typeRepository.Object, null, featureProvider.Object);
var attachedOwnerXamlType = new XamlType(typeof(AttachedOwner), typeRepository.Object, null, featureProvider.Object);
context.Setup(x => x.TypeRepository).Returns(typeRepository.Object);
typeRepository.Setup(x => x.GetByQualifiedName("Class1")).Returns(class1XamlType);
typeRepository.Setup(x => x.GetByQualifiedName("AttachedOwner")).Returns(attachedOwnerXamlType);
return context.Object;
}
private class Class1 : PerspexObject
{
public static readonly PerspexProperty<string> FooProperty =
PerspexProperty.Register<Class1, string>("Foo");
}
private class AttachedOwner
{
public static readonly PerspexProperty<string> AttachedProperty =
PerspexProperty.RegisterAttached<AttachedOwner, Class1, string>("Attached");
}
}
}

1
Tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj

@ -99,6 +99,7 @@
<ItemGroup>
<Compile Include="BindingDefinitionBuilder.cs" />
<Compile Include="ChangeBranchTest.cs" />
<Compile Include="Converters\PerspexPropertyConverterTest.cs" />
<Compile Include="DataContextChangeSynchronizerTest.cs" />
<Compile Include="Parsers\SelectorGrammarTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

25
src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyConverter.cs

@ -4,9 +4,8 @@
using System;
using System.Globalization;
using System.Linq;
using OmniXaml.ObjectAssembler;
using OmniXaml;
using OmniXaml.TypeConversion;
using Perspex.Markup.Xaml.Parsers;
using Perspex.Styling;
namespace Perspex.Markup.Xaml.Converters
@ -43,12 +42,26 @@ namespace Perspex.Markup.Xaml.Converters
if (type == null)
{
throw new InvalidOperationException($"Could not find type '{typeName}'.");
throw new XamlParseException($"Could not find type '{typeName}'.");
}
// TODO: Handle attached properties.
// TODO: Give decent error message for not found property.
return PerspexObject.GetRegisteredProperties(type).Single(x => x.Name == propertyName);
// First look for non-attached property on the type and then look for an attached property.
var property = PerspexObject.GetRegisteredProperties(type)
.FirstOrDefault(x => x.Name == propertyName && !x.IsAttached);
if (property == null)
{
property = PerspexObject.GetAttachedProperties(type)
.FirstOrDefault(x => x.Name == propertyName);
}
if (property == null)
{
throw new XamlParseException(
$"Could not find PerspexProperty '{typeName}'.{propertyName}.");
}
return property;
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)

31
src/Perspex.Base/PerspexObject.cs

@ -273,6 +273,23 @@ namespace Perspex
}
}
/// <summary>
/// Gets all attached <see cref="PerspexProperty"/>s registered by an owner.
/// </summary>
/// <param name="ownerType">The owner type.</param>
/// <returns>A collection of <see cref="PerspexProperty"/> definitions.</returns>
public static IEnumerable<PerspexProperty> GetAttachedProperties(Type ownerType)
{
List<PerspexProperty> list;
if (s_attached.TryGetValue(ownerType, out list))
{
return list;
}
return Enumerable.Empty<PerspexProperty>();
}
/// <summary>
/// Registers a <see cref="PerspexProperty"/> on a type.
/// </summary>
@ -299,6 +316,20 @@ namespace Perspex
{
list.Add(property);
}
if (property.IsAttached)
{
if (!s_attached.TryGetValue(property.OwnerType, out list))
{
list = new List<PerspexProperty>();
s_attached.Add(property.OwnerType, list);
}
if (!list.Contains(property))
{
list.Add(property);
}
}
}
/// <summary>

8
tests/Perspex.Base.UnitTests/PerspexObjectTests_Metadata.cs

@ -34,6 +34,14 @@ namespace Perspex.Base.UnitTests
Assert.Equal(new[] { "Bar", "Flob", "Fred", "Foo", "Baz", "Qux", "Attached" }, names);
}
[Fact]
public void GetAttachedProperties_Returns_Registered_Properties_For_Base_Types()
{
string[] names = PerspexObject.GetAttachedProperties(typeof(AttachedOwner)).Select(x => x.Name).ToArray();
Assert.Equal(new[] { "Attached" }, names);
}
private class Class1 : PerspexObject
{
public static readonly PerspexProperty<string> FooProperty =

Loading…
Cancel
Save