Browse Source

WIP: Added PerspexTypeFeatureProvider.

Code isn't right yet - tests pass but test application doesn't run.
pull/413/head
Steven Kirk 11 years ago
parent
commit
f777b036a3
  1. 3
      src/Markup/Perspex.Markup.Xaml/Context/PerspexParserFactory.cs
  2. 90
      src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs
  3. 175
      src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeFeatureProvider.cs
  4. 2
      src/Markup/Perspex.Markup.Xaml/OmniXAML
  5. 1
      src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
  6. 30
      src/Perspex.Base/Metadata/DependsOnAttribute.cs
  7. 1
      src/Perspex.Base/Perspex.Base.csproj

3
src/Markup/Perspex.Markup.Xaml/Context/PerspexParserFactory.cs

@ -3,12 +3,11 @@
using OmniXaml;
using OmniXaml.ObjectAssembler;
using OmniXaml.Parsers.Parser;
using OmniXaml.Parsers.ProtoParser;
namespace Perspex.Markup.Xaml.Context
{
using OmniXaml.Parsers.Parser;
public class PerspexParserFactory : IParserFactory
{
private readonly IRuntimeTypeSource runtimeTypeSource;

90
src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs

@ -25,104 +25,17 @@ namespace Perspex.Markup.Xaml.Context
public class PerspexRuntimeTypeSource : IRuntimeTypeSource
{
private static readonly IEnumerable<Assembly> ForcedAssemblies = new[]
{
typeof(PerspexObject).GetTypeInfo().Assembly,
typeof(Control).GetTypeInfo().Assembly,
typeof(Style).GetTypeInfo().Assembly,
typeof(DataTemplate).GetTypeInfo().Assembly,
typeof(SolidColorBrush).GetTypeInfo().Assembly,
typeof(IValueConverter).GetTypeInfo().Assembly,
};
private readonly RuntimeTypeSource inner;
public PerspexRuntimeTypeSource(ITypeFactory typeFactory)
{
var namespaceRegistry = new PerspexNamespaceRegistry();
var featureProvider = new TypeFeatureProvider(GetConverterProvider());
LoadFeatureProvider(featureProvider);
var featureProvider = new PerspexTypeFeatureProvider();
var typeRepository = new PerspexTypeRepository(namespaceRegistry, typeFactory, featureProvider);
inner = new RuntimeTypeSource(typeRepository, namespaceRegistry);
}
private static IEnumerable<Assembly> ScannedAssemblies
{
get
{
var platform = PerspexLocator.Current.GetService<IPclPlatformWrapper>();
if (platform != null)
{
return ForcedAssemblies.Concat(platform.GetLoadedAssemblies()).Distinct();
}
else
{
return ForcedAssemblies;
}
}
}
private void LoadFeatureProvider(ITypeFeatureProvider featureProvider)
{
featureProvider.RegisterMetadata(new GenericMetadata<Visual>().WithRuntimeNameProperty(d => d.Name));
featureProvider.RegisterMetadata(new GenericMetadata<Setter>().WithMemberDependency(x => x.Value, x => x.Property));
featureProvider.RegisterMetadata(
new GenericMetadata<SelectingItemsControl>()
.WithMemberDependency(x => x.SelectedIndex, x => x.Items)
.WithMemberDependency(x => x.SelectedItem, x => x.Items));
RegisteContentProperties(featureProvider);
}
private static void RegisteContentProperties(ITypeFeatureProvider featureProvider)
{
var typeAndAttribute = from type in ScannedAssemblies.AllExportedTypes()
let properties = type.GetTypeInfo().DeclaredProperties
from property in properties
let attr = property.GetCustomAttribute<ContentAttribute>()
where attr != null
select new { Type = type, Property = property, ContentAttribute = attr };
foreach (var t in typeAndAttribute)
{
featureProvider.RegisterMetadata(t.Type, new Metadata {ContentProperty = t.Property.Name});
}
}
private static ITypeConverterProvider GetConverterProvider()
{
var typeConverterProvider = new TypeConverterProvider();
var converters = new[]
{
new TypeConverterRegistration(typeof(IBitmap), new BitmapTypeConverter()),
new TypeConverterRegistration(typeof(Brush), new BrushTypeConverter()),
new TypeConverterRegistration(typeof(Color), new ColorTypeConverter()),
new TypeConverterRegistration(typeof(Classes), new ClassesTypeConverter()),
new TypeConverterRegistration(typeof(ColumnDefinitions), new ColumnDefinitionsTypeConverter()),
new TypeConverterRegistration(typeof(Geometry), new GeometryTypeConverter()),
new TypeConverterRegistration(typeof(GridLength), new GridLengthTypeConverter()),
new TypeConverterRegistration(typeof(KeyGesture), new KeyGestureConverter()),
new TypeConverterRegistration(typeof(PerspexList<double>), new PerspexListTypeConverter<double>()),
new TypeConverterRegistration(typeof(IMemberSelector), new MemberSelectorTypeConverter()),
new TypeConverterRegistration(typeof(Point), new PointTypeConverter()),
new TypeConverterRegistration(typeof(IList<Point>), new PointsListTypeConverter()),
new TypeConverterRegistration(typeof(PerspexProperty), new PerspexPropertyTypeConverter()),
new TypeConverterRegistration(typeof(RelativePoint), new RelativePointTypeConverter()),
new TypeConverterRegistration(typeof(RelativeRect), new RelativeRectTypeConverter()),
new TypeConverterRegistration(typeof(RowDefinitions), new RowDefinitionsTypeConverter()),
new TypeConverterRegistration(typeof(Selector), new SelectorTypeConverter()),
new TypeConverterRegistration(typeof(Thickness), new ThicknessTypeConverter()),
new TypeConverterRegistration(typeof(TimeSpan), new TimeSpanTypeConverter()),
new TypeConverterRegistration(typeof(Uri), new UriTypeConverter()),
new TypeConverterRegistration(typeof(Cursor), new CursorTypeConverter())
};
typeConverterProvider.AddAll(converters);
return typeConverterProvider;
}
public Namespace GetNamespace(string name)
{
return inner.GetNamespace(name);
@ -145,7 +58,6 @@ namespace Perspex.Markup.Xaml.Context
public IEnumerable<PrefixRegistration> RegisteredPrefixes => inner.RegisteredPrefixes;
public XamlType GetByType(Type type)
{
return inner.GetByType(type);

175
src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeFeatureProvider.cs

@ -0,0 +1,175 @@
// 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.Collections.Generic;
using System.Linq;
using System.Reflection;
using OmniXaml;
using OmniXaml.Builder;
using OmniXaml.TypeConversion;
using OmniXaml.TypeConversion.BuiltInConverters;
using OmniXaml.Typing;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Controls.Templates;
using Perspex.Input;
using Perspex.Markup.Xaml.Converters;
using Perspex.Media;
using Perspex.Media.Imaging;
using Perspex.Metadata;
using Perspex.Styling;
using OmniMetadata = OmniXaml.Typing.Metadata;
namespace Perspex.Markup.Xaml.Context
{
public class PerspexTypeFeatureProvider : ITypeFeatureProvider
{
private Dictionary<Type, OmniMetadata> _metadata =
new Dictionary<Type, OmniMetadata>();
private Dictionary<Type, TypeConverterRegistration> _typeConverters =
new Dictionary<Type, TypeConverterRegistration>();
public IEnumerable<TypeConverterRegistration> TypeConverters => _typeConverters.Values;
public PerspexTypeFeatureProvider()
{
RegisterTypeConverters();
}
public string GetContentPropertyName(Type type)
{
return GetMetadata(type)?.ContentProperty;
}
public OmniMetadata GetMetadata(Type type)
{
OmniMetadata result;
if (!_metadata.TryGetValue(type, out result))
{
result = LoadMetadata(type);
_metadata.Add(type, result);
}
return result;
}
public ITypeConverter GetTypeConverter(Type type)
{
TypeConverterRegistration result;
_typeConverters.TryGetValue(type, out result);
return result?.TypeConverter;
}
public void RegisterMetadata(Type type, OmniMetadata metadata)
{
_metadata.Add(type, metadata);
}
public void RegisterTypeConverter(Type type, ITypeConverter converter)
{
_typeConverters.Add(type, new TypeConverterRegistration(type, converter));
}
private static OmniMetadata LoadMetadata(Type type)
{
return new OmniMetadata
{
ContentProperty = GetContentProperty(type),
PropertyDependencies = GetPropertyDependencies(type),
RuntimePropertyName = type.GetRuntimeProperty("Name")?.Name,
};
}
private static string GetContentProperty(Type type)
{
while (type != null)
{
var properties = type.GetTypeInfo().DeclaredProperties
.Where(x => x.GetCustomAttribute<ContentAttribute>() != null);
string result = null;
foreach (var property in properties)
{
if (result != null)
{
throw new Exception($"Content property defined more than once on {type}.");
}
result = property.Name;
}
if (result != null)
{
return result;
}
type = type.GetTypeInfo().BaseType;
}
return null;
}
private static DependencyRegistrations GetPropertyDependencies(Type type)
{
var result = new List<DependencyRegistration>();
while (type != null)
{
var registrations = type.GetTypeInfo().DeclaredProperties
.Select(x => new
{
Property = x.Name,
Attributes = x.GetCustomAttributes<DependsOnAttribute>(),
})
.Where(x => x.Attributes.Any())
.SelectMany(x => x.Attributes.Select(y => new DependencyRegistration(x.Property, y.Name)));
result.AddRange(registrations);
type = type.GetTypeInfo().BaseType;
}
return result.Count > 0 ? new DependencyRegistrations(result) : null;
}
private void RegisterTypeConverters()
{
// HACK: For now these are hard-coded. Hopefully when the .NET Standard Platform
// is available we can use the System.ComponentModel.TypeConverters so don't want to
// spend time for now inventing a mechanism to register type converters if it's all
// going to change.
RegisterTypeConverter(typeof(string), new StringTypeConverter());
RegisterTypeConverter(typeof(int), new IntTypeConverter());
RegisterTypeConverter(typeof(long), new IntTypeConverter());
RegisterTypeConverter(typeof(short), new IntTypeConverter());
RegisterTypeConverter(typeof(double), new DoubleTypeConverter());
RegisterTypeConverter(typeof(float), new IntTypeConverter());
RegisterTypeConverter(typeof(bool), new BooleanConverter());
RegisterTypeConverter(typeof(Type), new TypeTypeConverter());
RegisterTypeConverter(typeof(IBitmap), new BitmapTypeConverter());
RegisterTypeConverter(typeof(Brush), new BrushTypeConverter());
RegisterTypeConverter(typeof(Color), new ColorTypeConverter());
RegisterTypeConverter(typeof(Classes), new ClassesTypeConverter());
RegisterTypeConverter(typeof(ColumnDefinitions), new ColumnDefinitionsTypeConverter());
RegisterTypeConverter(typeof(Geometry), new GeometryTypeConverter());
RegisterTypeConverter(typeof(GridLength), new GridLengthTypeConverter());
RegisterTypeConverter(typeof(KeyGesture), new KeyGestureConverter());
RegisterTypeConverter(typeof(PerspexList<double>), new PerspexListTypeConverter<double>());
RegisterTypeConverter(typeof(IMemberSelector), new MemberSelectorTypeConverter());
RegisterTypeConverter(typeof(Point), new PointTypeConverter());
RegisterTypeConverter(typeof(IList<Point>), new PointsListTypeConverter());
RegisterTypeConverter(typeof(PerspexProperty), new PerspexPropertyTypeConverter());
RegisterTypeConverter(typeof(RelativePoint), new RelativePointTypeConverter());
RegisterTypeConverter(typeof(RelativeRect), new RelativeRectTypeConverter());
RegisterTypeConverter(typeof(RowDefinitions), new RowDefinitionsTypeConverter());
RegisterTypeConverter(typeof(Selector), new SelectorTypeConverter());
RegisterTypeConverter(typeof(Thickness), new ThicknessTypeConverter());
RegisterTypeConverter(typeof(TimeSpan), new TimeSpanTypeConverter());
RegisterTypeConverter(typeof(Uri), new UriTypeConverter());
RegisterTypeConverter(typeof(Cursor), new CursorTypeConverter());
}
}
}

2
src/Markup/Perspex.Markup.Xaml/OmniXAML

@ -1 +1 @@
Subproject commit 2b28639da15e5f43f4b713e0b115d1bb41679cc6
Subproject commit 5ed61489b4db4578680004cd6ddbe811cdd91f8f

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

@ -44,6 +44,7 @@
<Compile Include="Context\PerspexAttachableXamlMember.cs" />
<Compile Include="Context\PerspexNamespaceRegistry.cs" />
<Compile Include="Context\PerspexObjectAssembler.cs" />
<Compile Include="Context\PerspexTypeFeatureProvider.cs" />
<Compile Include="Context\PerspexParserFactory.cs" />
<Compile Include="Context\PerspexRuntimeTypeSource.cs" />
<Compile Include="Context\PerspexTypeRepository.cs" />

30
src/Perspex.Base/Metadata/DependsOnAttribute.cs

@ -0,0 +1,30 @@
// 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;
namespace Perspex.Metadata
{
/// <summary>
/// Indicates that the property depends on the value of another property in markup.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class DependsOnAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="DependsOnAttribute"/> class.
/// </summary>
/// <param name="propertyName">
/// The name of the property that this property depends on.
/// </param>
public DependsOnAttribute(string propertyName)
{
Name = propertyName;
}
/// <summary>
/// Gets the name of the property that this property depends on.
/// </summary>
public string Name { get; }
}
}

1
src/Perspex.Base/Perspex.Base.csproj

@ -55,6 +55,7 @@
<Compile Include="DirectProperty.cs" />
<Compile Include="IPerspexObject.cs" />
<Compile Include="IStyledPropertyMetadata.cs" />
<Compile Include="Metadata\DependsOnAttribute.cs" />
<Compile Include="Metadata\ContentAttribute.cs" />
<Compile Include="PerspexDisposable.cs" />
<Compile Include="PerspexLocator.cs" />

Loading…
Cancel
Save