Browse Source

Reworked TypeConverters.

I started fixing #1559 and decided to rework our `TypeConverter` infrastructure a bit.

This PR renames `AvaloniaDefaultTypeConverters` to `AvaloniaTypeConverters` and allow registration of 3rd party converters here.

`AvaloniaTypeConverters` improves upon the type converter functionality in the BCL by providing the followinng extra functionality:

- Allow registering non-constructed generic types (such as `AvaloniaList<>`) - `AvaloniaTypeConverters` will do the sensible thing and create an `AvaloniaListConverter<T>` with the correct type
- If no type converter is provided, look for a a static `Parse(string)` method which can be used to create an implicit type converter

This allows us to remove a bunch of `TypeConverter`s which just called the relevant `Parse` method.

Fixes #1559
pull/1560/head
Steven Kirk 8 years ago
parent
commit
7588b16044
  1. 18
      src/Avalonia.Base/Collections/AvaloniaListConverter.cs
  2. 7
      src/Avalonia.Controls/Classes.cs
  3. 8
      src/Avalonia.Controls/ColumnDefinitions.cs
  4. 8
      src/Avalonia.Controls/RowDefinitions.cs
  5. 7
      src/Avalonia.Input/Cursors.cs
  6. 4
      src/Avalonia.Visuals/Media/Brush.cs
  7. 13
      src/Avalonia.Visuals/Media/BrushConverter.cs
  8. 7
      src/Avalonia.Visuals/Media/Geometry.cs
  9. 3
      src/Avalonia.Visuals/Media/IBrush.cs
  10. 15
      src/Avalonia.Visuals/Media/SolidColorBrush.cs
  11. 25
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  12. 80
      src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs
  13. 22
      src/Markup/Avalonia.Markup.Xaml/Converters/ClassesTypeConverter.cs
  14. 26
      src/Markup/Avalonia.Markup.Xaml/Converters/ColorTypeConverter.cs
  15. 24
      src/Markup/Avalonia.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs
  16. 19
      src/Markup/Avalonia.Markup.Xaml/Converters/CornerRadiusTypeConverter.cs
  17. 25
      src/Markup/Avalonia.Markup.Xaml/Converters/CursorTypeConverter.cs
  18. 24
      src/Markup/Avalonia.Markup.Xaml/Converters/GeometryTypeConverter.cs
  19. 24
      src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs
  20. 24
      src/Markup/Avalonia.Markup.Xaml/Converters/KeyGestureConverter.cs
  21. 23
      src/Markup/Avalonia.Markup.Xaml/Converters/MatrixTypeConverter.cs
  22. 5
      src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs
  23. 66
      src/Markup/Avalonia.Markup.Xaml/Converters/ParseTypeConverter.cs
  24. 23
      src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs
  25. 23
      src/Markup/Avalonia.Markup.Xaml/Converters/RectTypeConverter.cs
  26. 23
      src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs
  27. 23
      src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs
  28. 24
      src/Markup/Avalonia.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs
  29. 23
      src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs
  30. 23
      src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs
  31. 89
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs
  32. 2
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
  33. 5
      src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs
  34. 1
      tests/Avalonia.Base.UnitTests/Collections/AvaloniaListTests.cs

18
src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaListTypeConverter.cs → src/Avalonia.Base/Collections/AvaloniaListConverter.cs

@ -2,16 +2,16 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.ComponentModel;
using System.Globalization;
using Avalonia.Collections;
using Avalonia.Utilities;
namespace Avalonia.Markup.Xaml.Converters
namespace Avalonia.Collections
{
using Portable.Xaml.ComponentModel;
using System.ComponentModel;
public class AvaloniaListTypeConverter<T> : TypeConverter
/// <summary>
/// Creates an <see cref="AvaloniaList{T}"/> from a string representation.
/// </summary>
public class AvaloniaListConverter<T> : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
@ -21,13 +21,13 @@ namespace Avalonia.Markup.Xaml.Converters
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var result = new AvaloniaList<T>();
// TODO: Use StringTokenizer here.
var values = ((string)value).Split(',');
foreach (var s in values)
{
object v;
if (TypeUtilities.TryConvert(typeof(T), s, culture, out v))
if (TypeUtilities.TryConvert(typeof(T), s, culture, out var v))
{
result.Add((T)v);
}

7
src/Avalonia.Controls/Classes.cs

@ -41,6 +41,13 @@ namespace Avalonia.Controls
{
}
/// <summary>
/// Parses a classes string.
/// </summary>
/// <param name="s">The string.</param>
/// <returns>The <see cref="Classes"/>.</returns>
public static Classes Parse(string s) => new Classes(s.Split(' '));
/// <summary>
/// Adds a style class to the collection.
/// </summary>

8
src/Avalonia.Controls/ColumnDefinitions.cs

@ -1,7 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Globalization;
using System.Linq;
using Avalonia.Collections;
@ -29,5 +28,12 @@ namespace Avalonia.Controls
{
AddRange(GridLength.ParseLengths(s).Select(x => new ColumnDefinition(x)));
}
/// <summary>
/// Parses a string representation of column definitions collection.
/// </summary>
/// <param name="s">The column definitions string.</param>
/// <returns>The <see cref="ColumnDefinitions"/>.</returns>
public static ColumnDefinitions Parse(string s) => new ColumnDefinitions(s);
}
}

8
src/Avalonia.Controls/RowDefinitions.cs

@ -1,7 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Globalization;
using System.Linq;
using Avalonia.Collections;
@ -29,5 +28,12 @@ namespace Avalonia.Controls
{
AddRange(GridLength.ParseLengths(s).Select(x => new RowDefinition(x)));
}
/// <summary>
/// Parses a string representation of row definitions collection.
/// </summary>
/// <param name="s">The row definitions string.</param>
/// <returns>The <see cref="RowDefinitions"/>.</returns>
public static RowDefinitions Parse(string s) => new RowDefinitions(s);
}
}

7
src/Avalonia.Input/Cursors.cs

@ -65,6 +65,13 @@ namespace Avalonia.Input
public IPlatformHandle PlatformCursor { get; }
public static Cursor Parse(string s)
{
return Enum.TryParse<StandardCursorType>(s, true, out var t) ?
new Cursor(t) :
throw new ArgumentException($"Unrecognised cursor type '{s}'.");
}
private static IPlatformHandle GetCursor(StandardCursorType type)
{
var platform = AvaloniaLocator.Current.GetService<IStandardCursorFactory>();

4
src/Avalonia.Visuals/Media/Brush.cs

@ -2,14 +2,14 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Linq;
using System.Reflection;
using System.ComponentModel;
namespace Avalonia.Media
{
/// <summary>
/// Describes how an area is painted.
/// </summary>
[TypeConverter(typeof(BrushConverter))]
public abstract class Brush : AvaloniaObject, IBrush
{
/// <summary>

13
src/Markup/Avalonia.Markup.Xaml/Converters/BrushTypeConverter.cs → src/Avalonia.Visuals/Media/BrushConverter.cs

@ -2,16 +2,15 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.ComponentModel;
using System.Globalization;
using Avalonia.Media;
namespace Avalonia.Markup.Xaml.Converters
namespace Avalonia.Media
{
using Portable.Xaml.ComponentModel;
using System.ComponentModel;
public class BrushTypeConverter : TypeConverter
/// <summary>
/// Creates an <see cref="IBrush"/> from a string representation.
/// </summary>
public class BrushConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{

7
src/Avalonia.Visuals/Media/Geometry.cs

@ -69,6 +69,13 @@ namespace Avalonia.Media
set { SetValue(TransformProperty, value); }
}
/// <summary>
/// Creates a <see cref="Geometry"/> from a string.
/// </summary>
/// <param name="s">The string.</param>
/// <returns>A <see cref="StreamGeometry"/>.</returns>
public static Geometry Parse(string s) => StreamGeometry.Parse(s);
/// <summary>
/// Clones the geometry.
/// </summary>

3
src/Avalonia.Visuals/Media/IBrush.cs

@ -1,11 +1,14 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.ComponentModel;
namespace Avalonia.Media
{
/// <summary>
/// Describes how an area is painted.
/// </summary>
[TypeConverter(typeof(BrushConverter))]
public interface IBrush
{
/// <summary>

15
src/Avalonia.Visuals/Media/SolidColorBrush.cs

@ -52,6 +52,21 @@ namespace Avalonia.Media
set { SetValue(ColorProperty, value); }
}
/// <summary>
/// Parses a brush string.
/// </summary>
/// <param name="s">The brush string.</param>
/// <returns>The <see cref="Color"/>.</returns>
/// <remarks>
/// Whereas <see cref="Brush.Parse(string)"/> may return an immutable solid color brush,
/// this method always returns a mutable <see cref="SolidColorBrush"/>.
/// </remarks>
public static new SolidColorBrush Parse(string s)
{
var brush = (ISolidColorBrush)Brush.Parse(s);
return brush is SolidColorBrush solid ? solid : new SolidColorBrush(brush.Color);
}
/// <summary>
/// Returns a string representation of the brush.
/// </summary>

25
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -30,10 +30,10 @@
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AvaloniaXamlLoader.cs" />
<Compile Include="Converters\CornerRadiusTypeConverter.cs" />
<Compile Include="Converters\MatrixTypeConverter.cs" />
<Compile Include="Converters\RectTypeConverter.cs" />
<Compile Include="Converters\MemberSelectorTypeConverter.cs" />
<Compile Include="Converters\ParseTypeConverter.cs" />
<Compile Include="Converters\SetterValueTypeConverter.cs" />
<Compile Include="Converters\TimeSpanTypeConverter.cs" />
<Compile Include="Data\ResourceInclude.cs" />
<Compile Include="MarkupExtensions\DynamicResourceExtension.cs" />
<Compile Include="MarkupExtensions\StaticResourceExtension.cs" />
@ -42,32 +42,15 @@
<Compile Include="PortableXaml\AttributeExtensions.cs" />
<Compile Include="PortableXaml\AvaloniaMemberAttributeProvider.cs" />
<Compile Include="PortableXaml\AvaloniaNameScope.cs" />
<Compile Include="PortableXaml\AvaloniaDefaultTypeConverters.cs" />
<Compile Include="AvaloniaTypeConverters.cs" />
<Compile Include="PortableXaml\AvaloniaXamlObjectWriter.cs" />
<Compile Include="PortableXaml\AvaloniaRuntimeTypeProvider.cs" />
<Compile Include="PortableXaml\AvaloniaXamlSchemaContext.cs" />
<Compile Include="Converters\BitmapTypeConverter.cs" />
<Compile Include="Converters\BrushTypeConverter.cs" />
<Compile Include="Converters\ClassesTypeConverter.cs" />
<Compile Include="Converters\ColorTypeConverter.cs" />
<Compile Include="Converters\ColumnDefinitionsTypeConverter.cs" />
<Compile Include="Converters\CursorTypeConverter.cs" />
<Compile Include="Converters\GeometryTypeConverter.cs" />
<Compile Include="Converters\GridLengthTypeConverter.cs" />
<Compile Include="Converters\IconTypeConverter.cs" />
<Compile Include="Converters\KeyGestureConverter.cs" />
<Compile Include="Converters\MemberSelectorTypeConverter.cs" />
<Compile Include="Converters\AvaloniaListTypeConverter.cs" />
<Compile Include="Converters\AvaloniaPropertyTypeConverter.cs" />
<Compile Include="Converters\PointsListTypeConverter.cs" />
<Compile Include="Converters\SizeTypeConverter.cs" />
<Compile Include="Converters\PointTypeConverter.cs" />
<Compile Include="Converters\RelativePointTypeConverter.cs" />
<Compile Include="Converters\RelativeRectTypeConverter.cs" />
<Compile Include="Converters\RowDefinitionsTypeConverter.cs" />
<Compile Include="Converters\SelectorTypeConverter.cs" />
<Compile Include="Converters\ThicknessTypeConverter.cs" />
<Compile Include="Converters\TimeSpanTypeConverter.cs" />
<Compile Include="Data\Binding.cs" />
<Compile Include="Data\DelayedBinding.cs" />
<Compile Include="Data\MultiBinding.cs" />

80
src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs

@ -0,0 +1,80 @@
using System;
using System.ComponentModel;
using System.Collections.Generic;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Markup.Xaml.Converters;
using Avalonia.Media.Imaging;
using Avalonia.Styling;
using Avalonia.Controls.Templates;
namespace Avalonia.Markup.Xaml
{
/// <summary>
/// Maintains a repository of <see cref="TypeConverter"/>s for XAML parsing on top of those
/// maintained by <see cref="TypeDescriptor"/>.
/// </summary>
/// <remarks>
/// The default method of defining type converters using <see cref="TypeConverterAttribute"/>
/// isn't powerful enough for our purposes:
///
/// - It doesn't handle non-constructed generic types (such as <see cref="AvaloniaList{T}"/>)
/// - Type converters which require XAML features cannot be defined in non-XAML assemblies and
/// so can't be referenced using <see cref="TypeConverterAttribute"/>
/// - Many types have a static `Parse(string)` method which can be used implicitly; this class
/// detects such methods and auto-creates a type converter
/// </remarks>
public static class AvaloniaTypeConverters
{
private static Dictionary<Type, Type> _converters = new Dictionary<Type, Type>()
{
{ typeof(AvaloniaList<>), typeof(AvaloniaListConverter<>) },
{ typeof(AvaloniaProperty), typeof(AvaloniaPropertyTypeConverter) },
{ typeof(IBitmap), typeof(BitmapTypeConverter) },
{ typeof(IList<Point>), typeof(PointsListTypeConverter) },
{ typeof(IMemberSelector), typeof(MemberSelectorTypeConverter) },
{ typeof(Selector), typeof(SelectorTypeConverter) },
{ typeof(TimeSpan), typeof(TimeSpanTypeConverter) },
{ typeof(WindowIcon), typeof(IconTypeConverter) },
};
/// <summary>
/// Tries to lookup a <see cref="TypeConverter"/> for a type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>The type converter.</returns>
public static Type GetTypeConverter(Type type)
{
if (_converters.TryGetValue(type, out var result))
{
return result;
}
// Converters for non-constructed generic types can't be specified using
// TypeConverterAttribute. Allow them to be registered here and handle them sanely.
if (type.IsConstructedGenericType &&
_converters.TryGetValue(type.GetGenericTypeDefinition(), out result))
{
return result?.MakeGenericType(type.GetGenericArguments());
}
// If the type has a static Parse method, use that.
if (ParseTypeConverter.HasParseMethod(type))
{
result = typeof(ParseTypeConverter<>).MakeGenericType(type);
_converters.Add(type, result);
return result;
}
_converters.Add(type, null);
return null;
}
/// <summary>
/// Registers a type converter for a type.
/// </summary>
/// <param name="type">The type. Maybe be a non-constructed generic type.</param>
/// <param name="converterType">The converter type. Maybe be a non-constructed generic type.</param>
public static void Register(Type type, Type converterType) => _converters[type] = converterType;
}
}

22
src/Markup/Avalonia.Markup.Xaml/Converters/ClassesTypeConverter.cs

@ -1,22 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
using Avalonia.Controls;
using System.ComponentModel;
namespace Avalonia.Markup.Xaml.Converters
{
public class ClassesTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return new Classes(((string)value).Split(' '));
}
}
}

26
src/Markup/Avalonia.Markup.Xaml/Converters/ColorTypeConverter.cs

@ -1,26 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
using Avalonia.Media;
using System.ComponentModel;
namespace Avalonia.Markup.Xaml.Converters
{
public class ColorTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Color.Parse((string)value);
}
}
}

24
src/Markup/Avalonia.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs

@ -1,24 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
using Avalonia.Controls;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class ColumnDefinitionsTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return new ColumnDefinitions((string)value);
}
}
}

19
src/Markup/Avalonia.Markup.Xaml/Converters/CornerRadiusTypeConverter.cs

@ -1,19 +0,0 @@
using System;
using System.ComponentModel;
using System.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
public class CornerRadiusTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return CornerRadius.Parse((string)value);
}
}
}

25
src/Markup/Avalonia.Markup.Xaml/Converters/CursorTypeConverter.cs

@ -1,25 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
using Avalonia.Input;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class CursorTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var cursor = (StandardCursorType)Enum.Parse(typeof(StandardCursorType), ((string)value).Trim(), true);
return new Cursor(cursor);
}
}
}

24
src/Markup/Avalonia.Markup.Xaml/Converters/GeometryTypeConverter.cs

@ -1,24 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
using Avalonia.Media;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class GeometryTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return StreamGeometry.Parse((string)value);
}
}
}

24
src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs

@ -1,24 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
using Avalonia.Controls;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class GridLengthTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return GridLength.Parse((string)value);
}
}
}

24
src/Markup/Avalonia.Markup.Xaml/Converters/KeyGestureConverter.cs

@ -1,24 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
using Avalonia.Input;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class KeyGestureConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return KeyGesture.Parse((string)value);
}
}
}

23
src/Markup/Avalonia.Markup.Xaml/Converters/MatrixTypeConverter.cs

@ -1,23 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class MatrixTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Matrix.Parse((string)value);
}
}
}

5
src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs

@ -18,10 +18,7 @@ namespace Avalonia.Markup.Xaml.Converters
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return new MemberSelector
{
MemberName = (string)value,
};
return MemberSelector.Parse((string)value);
}
}
}

66
src/Markup/Avalonia.Markup.Xaml/Converters/ParseTypeConverter.cs

@ -0,0 +1,66 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
namespace Avalonia.Markup.Xaml.Converters
{
/// <summary>
/// Base class for type converters which call a static Parse method.
/// </summary>
public abstract class ParseTypeConverter : TypeConverter
{
protected const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
protected static readonly Type[] StringParameter = new[] { typeof(string) };
protected static readonly Type[] StringIFormatProviderParameters = new[] { typeof(string), typeof(IFormatProvider) };
/// <summary>
/// Checks whether a type has a suitable Parse method.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>True if the type has a suitable parse method, otherwise false.</returns>
public static bool HasParseMethod(Type type)
{
return type.GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null) != null ||
type.GetMethod("Parse", PublicStatic, null, StringParameter, null) != null;
}
}
/// <summary>
/// A type converter which calls a static Parse method.
/// </summary>
/// <typeparam name="T">The type with the Parse method.</typeparam>
public class ParseTypeConverter<T> : ParseTypeConverter
{
private static MethodInfo _parseMethod;
private static bool _acceptsCulture;
static ParseTypeConverter()
{
_parseMethod = typeof(T).GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null);
_acceptsCulture = _parseMethod != null;
if (_parseMethod == null)
{
_parseMethod = typeof(T).GetMethod("Parse", PublicStatic, null, StringParameter, null);
}
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return _parseMethod != null && sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value != null && _parseMethod != null)
{
return _acceptsCulture ?
_parseMethod.Invoke(null, new[] { value, culture }) :
_parseMethod.Invoke(null, new[] { value });
}
return null;
}
}
}

23
src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs

@ -1,23 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class PointTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Point.Parse((string)value);
}
}
}

23
src/Markup/Avalonia.Markup.Xaml/Converters/RectTypeConverter.cs

@ -1,23 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class RectTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Rect.Parse((string)value);
}
}
}

23
src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs

@ -1,23 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class RelativePointTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return RelativePoint.Parse((string)value);
}
}
}

23
src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs

@ -1,23 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class RelativeRectTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return RelativeRect.Parse((string)value);
}
}
}

24
src/Markup/Avalonia.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs

@ -1,24 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
using Avalonia.Controls;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class RowDefinitionsTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return new RowDefinitions((string)value);
}
}
}

23
src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs

@ -1,23 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class SizeTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Size.Parse((string)value);
}
}
}

23
src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs

@ -1,23 +0,0 @@
// Copyright (c) The Avalonia 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.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class ThicknessTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Thickness.Parse((string)value);
}
}
}

89
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs

@ -1,89 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using Avalonia.Markup.Xaml.Converters;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Styling;
using Portable.Xaml.ComponentModel;
using System.ComponentModel;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Collections;
using Avalonia.Controls.Templates;
namespace Avalonia.Markup.Xaml.PortableXaml
{
public class AvaloniaDefaultTypeConverters
{
private static Dictionary<Type, Type> _defaultConverters = new Dictionary<Type, Type>()
{
//avalonia default converters
{ typeof(IBitmap), typeof(BitmapTypeConverter)},
{ typeof(IBrush), typeof(BrushTypeConverter) },
{ typeof(Color), typeof(ColorTypeConverter) },
{ typeof(Classes), typeof(ClassesTypeConverter) },
{ typeof(ColumnDefinitions), typeof(ColumnDefinitionsTypeConverter) },
//{ typeof(DateTime), typeof(DateTimeTypeConverter) },
{ typeof(Geometry), typeof(GeometryTypeConverter) },
{ typeof(GridLength), typeof(GridLengthTypeConverter) },
{ typeof(KeyGesture), typeof(KeyGestureConverter) },
{ typeof(AvaloniaList<double>), typeof(AvaloniaListTypeConverter<double>) },
{ typeof(IMemberSelector), typeof(MemberSelectorTypeConverter) },
{ typeof(Point), typeof(PointTypeConverter) },
{ typeof(Matrix), typeof(MatrixTypeConverter) },
{ typeof(IList<Point>), typeof(PointsListTypeConverter) },
{ typeof(AvaloniaProperty), typeof(AvaloniaPropertyTypeConverter) },
{ typeof(RelativePoint), typeof(RelativePointTypeConverter) },
{ typeof(RelativeRect), typeof(RelativeRectTypeConverter) },
{ typeof(RowDefinitions), typeof(RowDefinitionsTypeConverter) },
{ typeof(Size), typeof(SizeTypeConverter) },
{ typeof(Rect), typeof(RectTypeConverter) },
{ typeof(Selector), typeof(SelectorTypeConverter)},
{ typeof(SolidColorBrush), typeof(BrushTypeConverter) },
{ typeof(Thickness), typeof(ThicknessTypeConverter) },
{ typeof(CornerRadius), typeof(CornerRadiusTypeConverter) },
{ typeof(TimeSpan), typeof(TimeSpanTypeConverter) },
//{ typeof(Uri), typeof(Converters.UriTypeConverter) },
{ typeof(Cursor), typeof(CursorTypeConverter) },
{ typeof(WindowIcon), typeof(IconTypeConverter) },
//{ typeof(FontWeight), typeof(FontWeightConverter) },
};
public static Type GetTypeConverter(Type type)
{
Type converterType;
if (_defaultConverters.TryGetValue(type, out converterType))
{
return converterType;
}
//TODO: probably a smarter way to handle types
//is it needed ??
//Type curType = type;
//while (curType != null)
//{
// if (_defaultConverters.TryGetValue(curType, out converterType))
// {
// if (curType != type)
// {
// _defaultConverters[curType] = converterType;
// }
// return converterType;
// }
// else
// {
// _defaultConverters[curType] = null;
// }
// curType = curType.GetTypeInfo().BaseType;
//}
return null;
}
}
}

2
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs

@ -46,7 +46,7 @@ namespace Avalonia.Markup.Xaml.PortableXaml
if (result == null)
{
var convType = AvaloniaDefaultTypeConverters.GetTypeConverter(_type);
var convType = AvaloniaTypeConverters.GetTypeConverter(_type);
if (convType != null)
{

5
src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs

@ -25,6 +25,11 @@ namespace Avalonia.Markup.Xaml.Templates
}
}
public static MemberSelector Parse(string s)
{
return new MemberSelector { MemberName = s };
}
public object Select(object o)
{
if (string.IsNullOrEmpty(MemberName))

1
tests/Avalonia.Base.UnitTests/Collections/AvaloniaListTests.cs

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using Avalonia.Collections;
using Xunit;

Loading…
Cancel
Save