Skip to content

Commit

Permalink
[X] Add compiled converters
Browse files Browse the repository at this point in the history
- Add compiled converters for Flex enums
- and for FlexBasis
- and for for FlowDirection
- Also moves Flowdirection converter attribute from the property to the
  Type, and fix the Design assembly accordingly

- fixes #6547
  • Loading branch information
StephaneDelcroix committed May 17, 2022
1 parent c7a04d7 commit 8f594eb
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 90 deletions.

This file was deleted.

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using Microsoft.Maui.Controls.Build.Tasks;
using Microsoft.Maui.Controls.Xaml;
using Mono.Cecil.Cil;

namespace Microsoft.Maui.Controls.XamlC
{
class EnumTypeConverter<TEnum> : ICompiledTypeConverter where TEnum: struct
{
public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
{
if (!string.IsNullOrEmpty(value))
{
value = value.Trim();
if (Enum.TryParse(value, out TEnum enumValue))
{
yield return Instruction.Create(OpCodes.Ldc_I4, (int)(object)enumValue);
yield break;
}
}
throw new BuildException(BuildExceptionCode.Conversion, node, null, value, typeof(TEnum));
}
}
}
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.Maui.Controls.Build.Tasks;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Layouts;
using Mono.Cecil.Cil;

namespace Microsoft.Maui.Controls.XamlC
{
class FlexBasisTypeConverter : ICompiledTypeConverter
{
public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
{
var module = context.Body.Method.Module;
if (!string.IsNullOrEmpty(value))
{
value = value.Trim();
if (value == "Auto")
{
yield return Instruction.Create(OpCodes.Ldsfld,
module.ImportFieldReference(("Microsoft.Maui", "Microsoft.Maui.Layouts", "FlexBasis"),
"Auto",
isStatic: true));
yield break;
}
if (value.EndsWith("%", StringComparison.OrdinalIgnoreCase)
&& float.TryParse(value.Substring(0, value.Length - 1), NumberStyles.Number, CultureInfo.InvariantCulture, out float relflex))
{
yield return Instruction.Create(OpCodes.Ldc_R4, (float)(relflex / 100));
yield return Instruction.Create(OpCodes.Ldc_I4_1); //isRelative: true
yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference(("Microsoft.Maui", "Microsoft.Maui.Layouts", "FlexBasis"), parameterTypes: new[] {
("mscorlib", "System", "Single"),
("mscorlib", "System", "Boolean")}));
yield break;
}
if (float.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out float flex))
{
yield return Instruction.Create(OpCodes.Ldc_R4, flex);
yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference(("Microsoft.Maui", "Microsoft.Maui.Layouts", "FlexBasis"), parameterTypes: new[] {
("mscorlib", "System", "Single")}));
yield break;
}
}
throw new BuildException(BuildExceptionCode.Conversion, node, null, value, typeof(FlexBasis));
}
}
}
@@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Maui.Controls.Build.Tasks;
using Microsoft.Maui.Controls.Xaml;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace Microsoft.Maui.Controls.XamlC
Expand All @@ -25,7 +23,7 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
}

#pragma warning disable CS0612 // Type or member is obsolete
if (Enum.TryParse<NamedSize>(value, out NamedSize namedSize))
if (Enum.TryParse(value, out NamedSize namedSize))
{
//Device.GetNamedSize(namedSize, targetObject.GetType())
yield return Instruction.Create(OpCodes.Ldc_I4, (int)namedSize);
Expand Down
12 changes: 10 additions & 2 deletions src/Controls/src/Build.Tasks/NodeILExtensions.cs
Expand Up @@ -155,14 +155,22 @@ static T TryFormat<T>(Func<string, T> func, IXmlLineInfo lineInfo, string str)
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "ThicknessTypeConverter")), typeof(ThicknessTypeConverter) },
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "CornerRadiusTypeConverter")), typeof(CornerRadiusTypeConverter) },
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "EasingTypeConverter")), typeof(EasingTypeConverter) },
{ module.ImportReference(("Microsoft.Maui.Graphics", "Microsoft.Maui.Graphics.Converters", "ColorTypeConverter")), typeof(ColorTypeConverter) }
{ module.ImportReference(("Microsoft.Maui.Graphics", "Microsoft.Maui.Graphics.Converters", "ColorTypeConverter")), typeof(ColorTypeConverter) },
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexJustifyTypeConverter")), typeof(EnumTypeConverter<Layouts.FlexJustify>) },
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexDirectionTypeConverter")), typeof(EnumTypeConverter<Layouts.FlexDirection>) },
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexAlignContentTypeConverter")), typeof(EnumTypeConverter<Layouts.FlexAlignContent>) },
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexAlignItemsTypeConverter")), typeof(EnumTypeConverter<Layouts.FlexAlignItems>) },
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexAlignSelfTypeConverter")), typeof(EnumTypeConverter<Layouts.FlexAlignSelf>) },
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexWrapTypeConverter")), typeof(EnumTypeConverter<Layouts.FlexWrap>) },
{ module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexBasisTypeConverter")), typeof(FlexBasisTypeConverter) },
};
}

var str = (string)node.Value;
//If the TypeConverter has a ProvideCompiledAttribute that can be resolved, shortcut this
Type compiledConverterType;
if (typeConverter?.GetCustomAttribute(module, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.Xaml", "ProvideCompiledAttribute"))?.ConstructorArguments?.First().Value is string compiledConverterName && (compiledConverterType = Type.GetType(compiledConverterName)) != null
if ( typeConverter?.GetCustomAttribute(module, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.Xaml", "ProvideCompiledAttribute"))?.ConstructorArguments?.First().Value is string compiledConverterName
&& (compiledConverterType = Type.GetType(compiledConverterName)) != null
|| (typeConverter != null && KnownCompiledTypeConverters.TryGetValue(typeConverter, out compiledConverterType)))
{
var compiledConverter = Activator.CreateInstance(compiledConverterType);
Expand Down
4 changes: 2 additions & 2 deletions src/Controls/src/Core.Design/AttributeTableBuilder.cs
Expand Up @@ -30,7 +30,7 @@ public AttributeTableBuilder()
AddMemberAttributes("Microsoft.Maui.Controls.VisualElement", "Visual",
new TypeConverterAttribute(typeof(VisualDesignTypeConverter)));

AddMemberAttributes("Microsoft.Maui.Controls.VisualElement", "FlowDirection",
AddTypeAttributes("Microsoft.Maui.FlowDirection",
new TypeConverterAttribute(typeof(FlowDirectionDesignTypeConverter)));

AddMemberAttributes("Microsoft.Maui.Controls.ItemsView", "ItemsLayout",
Expand Down Expand Up @@ -95,4 +95,4 @@ private void AddTypeAttributes(string typeName, params Attribute[] attribs)
private void AddMemberAttributes(string typeName, string memberName, params Attribute[] attribs)
=> AddCallback(typeName, builder => builder.AddCustomAttributes(memberName, attribs));
}
}
}
1 change: 0 additions & 1 deletion src/Controls/src/Core/VisualElement.cs
Expand Up @@ -332,7 +332,6 @@ void InvalidateGradientBrushRequested(object sender, EventArgs e)
IFlowDirectionController FlowController => this;

/// <include file="../../docs/Microsoft.Maui.Controls/VisualElement.xml" path="//Member[@MemberName='FlowDirection']/Docs" />
[System.ComponentModel.TypeConverter(typeof(FlowDirectionConverter))]
public FlowDirection FlowDirection
{
get { return (FlowDirection)GetValue(FlowDirectionProperty); }
Expand Down
1 change: 0 additions & 1 deletion src/Controls/src/Xaml/ApplyPropertiesVisitor.cs
Expand Up @@ -377,7 +377,6 @@ public static void SetPropertyValue(object xamlelement, XmlName propertyName, ob
context.ExceptionHandler(xpe);
else
throw xpe;

}

//Used by HotReload, do not change signature
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Converters/FlexEnumsConverters.cs
Expand Up @@ -218,9 +218,9 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c
var strValue = value?.ToString();
if (strValue != null)
{
value = strValue.Trim();
if (strValue.Equals("auto", StringComparison.OrdinalIgnoreCase))
return FlexBasis.Auto;
value = strValue.Trim();
if (strValue.EndsWith("%", StringComparison.OrdinalIgnoreCase) && float.TryParse(strValue.Substring(0, strValue.Length - 1), NumberStyles.Number, CultureInfo.InvariantCulture, out float relflex))
return new FlexBasis(relflex / 100, isRelative: true);
if (float.TryParse(strValue, NumberStyles.Number, CultureInfo.InvariantCulture, out float flex))
Expand Down
Expand Up @@ -2,20 +2,17 @@
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.Maui.Controls
#nullable disable
namespace Microsoft.Maui.Converters
{
/// <include file="../../docs/Microsoft.Maui.Controls/FlowDirectionConverter.xml" path="Type[@FullName='Microsoft.Maui.Controls.FlowDirectionConverter']/Docs" />
public class FlowDirectionConverter : TypeConverter
public class FlowDirectionTypeConverter : TypeConverter
{
/// <include file="../../docs/Microsoft.Maui.Controls/FlowDirectionConverter.xml" path="//Member[@MemberName='CanConvertFrom']/Docs" />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
=> sourceType == typeof(string);

/// <include file="../../docs/Microsoft.Maui.Controls/FlowDirectionConverter.xml" path="//Member[@MemberName='CanConvertTo']/Docs" />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
=> destinationType == typeof(string);

/// <include file="../../docs/Microsoft.Maui.Controls/FlowDirectionConverter.xml" path="//Member[@MemberName='ConvertFrom']/Docs" />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var strValue = value?.ToString();
Expand All @@ -35,7 +32,6 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", strValue, typeof(FlowDirection)));
}

/// <include file="../../docs/Microsoft.Maui.Controls/FlowDirectionConverter.xml" path="//Member[@MemberName='ConvertTo']/Docs" />
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value is not FlowDirection direction)
Expand Down
8 changes: 4 additions & 4 deletions src/Core/src/Layouts/FlexEnums.cs
Expand Up @@ -75,10 +75,12 @@ public struct FlexBasis
{
bool _isLength;
bool _isRelative;
public static FlexBasis Auto = new();
public float Length { get; }
internal bool IsAuto => !_isLength && !_isRelative;
internal bool IsRelative => _isRelative;

public static FlexBasis Auto = new();

public FlexBasis(float length, bool isRelative = false)
{
if (length < 0)
Expand All @@ -91,8 +93,6 @@ public FlexBasis(float length, bool isRelative = false)
}

public static implicit operator FlexBasis(float length)
{
return new FlexBasis(length);
}
=> new FlexBasis(length);
}
}
5 changes: 4 additions & 1 deletion src/Core/src/Primitives/FlowDirection.cs
@@ -1,6 +1,9 @@
namespace Microsoft.Maui
using System.ComponentModel;

namespace Microsoft.Maui
{
/// <include file="../../docs/Microsoft.Maui/FlowDirection.xml" path="Type[@FullName='Microsoft.Maui.FlowDirection']/Docs" />
[TypeConverter(typeof(Converters.FlowDirectionTypeConverter))]
public enum FlowDirection
{
/// <include file="../../docs/Microsoft.Maui/FlowDirection.xml" path="//Member[@MemberName='MatchParent']/Docs" />
Expand Down

0 comments on commit 8f594eb

Please sign in to comment.