Browse Source

Init AvaloniaListAttribute

pull/11073/head
Max Katz 3 years ago
parent
commit
38c1cc95c6
  1. 12
      src/Avalonia.Base/Metadata/AvaloniaListAttribute.cs
  2. 7
      src/Avalonia.Controls/Shapes/Polygon.cs
  3. 6
      src/Avalonia.Controls/Shapes/Polyline.cs
  4. 118
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs
  5. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

12
src/Avalonia.Base/Metadata/AvaloniaListAttribute.cs

@ -0,0 +1,12 @@
using System;
namespace Avalonia.Metadata;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class AvaloniaListAttribute : Attribute
{
public string[]? Separators { get; init; }
// StringSplitOptions.TrimEntries = 2, but only on net6 target.
public StringSplitOptions SplitOptions { get; init; } = StringSplitOptions.RemoveEmptyEntries | (StringSplitOptions)2;
}

7
src/Avalonia.Controls/Shapes/Polygon.cs

@ -1,19 +1,18 @@
using System.Collections.Generic;
using Avalonia.Media;
namespace Avalonia.Controls.Shapes
{
public class Polygon : Shape
{
public static readonly StyledProperty<IList<Point>> PointsProperty =
AvaloniaProperty.Register<Polygon, IList<Point>>("Points");
public static readonly StyledProperty<Points> PointsProperty =
AvaloniaProperty.Register<Polygon, Points>("Points");
static Polygon()
{
AffectsGeometry<Polygon>(PointsProperty);
}
public IList<Point> Points
public Points Points
{
get { return GetValue(PointsProperty); }
set { SetValue(PointsProperty, value); }

6
src/Avalonia.Controls/Shapes/Polyline.cs

@ -5,8 +5,8 @@ namespace Avalonia.Controls.Shapes
{
public class Polyline: Shape
{
public static readonly StyledProperty<IList<Point>> PointsProperty =
AvaloniaProperty.Register<Polyline, IList<Point>>("Points");
public static readonly StyledProperty<Points> PointsProperty =
AvaloniaProperty.Register<Polyline, Points>("Points");
static Polyline()
{
@ -14,7 +14,7 @@ namespace Avalonia.Controls.Shapes
AffectsGeometry<Polyline>(PointsProperty);
}
public IList<Point> Points
public Points Points
{
get { return GetValue(PointsProperty); }
set { SetValue(PointsProperty, value); }

118
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs

@ -198,6 +198,29 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a grid length", node);
}
}
if (type.Equals(types.ColumnDefinition) || type.Equals(types.RowDefinition))
{
try
{
var gridLength = GridLength.Parse(text);
result = new AvaloniaXamlIlGridLengthAstNode(node, types, gridLength);
var definitionConstructorGridLength = type.GetConstructor(new List<IXamlType> {types.GridLength});
var lengthNode = new AvaloniaXamlIlGridLengthAstNode(node, types, gridLength);
var definitionTypeRef = new XamlAstClrTypeReference(node, type, false);
result = new XamlAstNewClrObjectNode(node, definitionTypeRef,
definitionConstructorGridLength, new List<IXamlAstValueNode> {lengthNode});
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a grid length", node);
}
}
if (type.Equals(types.Cursor))
{
@ -211,16 +234,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
}
if (type.Equals(types.ColumnDefinitions))
{
return ConvertDefinitionList(node, text, types, types.ColumnDefinitions, types.ColumnDefinition, "column definitions", out result);
}
if (type.Equals(types.RowDefinitions))
{
return ConvertDefinitionList(node, text, types, types.RowDefinitions, types.RowDefinition, "row definitions", out result);
}
if (types.IBrush.IsAssignableFrom(type))
{
if (Color.TryParse(text, out Color color))
@ -295,46 +308,69 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
}
result = null;
return false;
}
private static bool ConvertDefinitionList(
IXamlAstValueNode node,
string text,
AvaloniaXamlIlWellKnownTypes types,
IXamlType listType,
IXamlType elementType,
string errorDisplayName,
out IXamlAstValueNode result)
{
try
// Keep it in the end, so more specific parsers can be applied.
var itemType = GetElementType(type, context.Configuration.WellKnownTypes);
if (itemType is not null
&& types.AvaloniaList.MakeGenericType(itemType).IsAssignableFrom(type))
{
var lengths = GridLength.ParseLengths(text);
var definitionTypeRef = new XamlAstClrTypeReference(node, elementType, false);
var definitionConstructorGridLength = elementType.GetConstructor(new List<IXamlType> {types.GridLength});
const StringSplitOptions trimOption = (StringSplitOptions)2; // StringSplitOptions.TrimEntries
var separators = new[] { "," };
var splitOptions = StringSplitOptions.RemoveEmptyEntries | trimOption;
IXamlAstValueNode CreateDefinitionNode(GridLength length)
var attribute = type.CustomAttributes.FirstOrDefault(a => a.Type == types.AvaloniaListAttribute);
if (attribute is not null)
{
var lengthNode = new AvaloniaXamlIlGridLengthAstNode(node, types, length);
return new XamlAstNewClrObjectNode(node, definitionTypeRef,
definitionConstructorGridLength, new List<IXamlAstValueNode> {lengthNode});
if (attribute.Properties.TryGetValue("Separators", out var separatorsArray))
{
separators = ((Array)separatorsArray)?.OfType<string>().ToArray();
}
if (attribute.Properties.TryGetValue("SplitOptions", out var splitOptionsObj))
{
splitOptions = (StringSplitOptions)splitOptionsObj;
}
}
var items = text.Split(separators, splitOptions ^ trimOption);
// Compiler targets netstandard, so we need to emulate StringSplitOptions.TrimEntries, if it was requested.
if (splitOptions.HasFlag(trimOption))
{
items = items.Select(i => i.Trim()).ToArray();
}
var definitionNodes =
new List<IXamlAstValueNode>(lengths.Select(CreateDefinitionNode));
if (itemType is null)
{
throw new XamlX.XamlLoadException($"Type '{type.Name}' is not a collection type.", node);
}
result = new AvaloniaXamlIlAvaloniaListConstantAstNode(node, types, listType, elementType, definitionNodes);
var nodes = new IXamlAstValueNode[items.Length];
for (var index = 0; index < items.Length; index++)
{
var success = XamlTransformHelpers.TryGetCorrectlyTypedValue(
context,
new XamlAstTextNode(node, items[index], true, context.Configuration.WellKnownTypes.String),
itemType, out var itemNode);
if (!success)
{
result = null;
return false;
}
nodes[index] = itemNode;
}
result = new AvaloniaXamlIlAvaloniaListConstantAstNode(node, types, type, itemType, nodes);
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a {errorDisplayName}", node);
}
result = null;
return false;
}
private static IXamlType GetElementType(IXamlType type, XamlTypeWellKnownTypes types)
{
return type.GetAllInterfaces().FirstOrDefault(i =>
i.FullName.StartsWith(types.IEnumerableT.FullName))?
.GenericArguments[0];
}
}
}

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -33,6 +33,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType InheritDataTypeFromItemsAttribute { get; }
public IXamlType MarkupExtensionOptionAttribute { get; }
public IXamlType MarkupExtensionDefaultOptionAttribute { get; }
public IXamlType AvaloniaListAttribute { get; }
public IXamlType AvaloniaList { get; }
public IXamlType OnExtensionType { get; }
public IXamlType UnsetValueType { get; }
public IXamlType StyledElement { get; }
@ -141,6 +143,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
InheritDataTypeFromItemsAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.InheritDataTypeFromItemsAttribute");
MarkupExtensionOptionAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.MarkupExtensionOptionAttribute");
MarkupExtensionDefaultOptionAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.MarkupExtensionDefaultOptionAttribute");
AvaloniaListAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.AvaloniaListAttribute");
AvaloniaList = cfg.TypeSystem.GetType("Avalonia.Collections.AvaloniaList`1");
OnExtensionType = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.On");
AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, AvaloniaObject,
AvaloniaProperty,

Loading…
Cancel
Save