From b4f6281a9b24cb5b3b7dd67922de3a6cb4271bc6 Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Tue, 17 May 2022 09:33:10 +0200 Subject: [PATCH] [X] Add compiled converters - 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 --- .../FlowDirectionConverter.xml | 68 ------------------- .../CompiledConverters/EnumTypeConverter.cs | 25 +++++++ .../FlexBasisTypeConverter.cs | 50 ++++++++++++++ .../FontSizeTypeConverter.cs | 4 +- .../src/Build.Tasks/NodeILExtensions.cs | 14 +++- .../src/Core.Design/AttributeTableBuilder.cs | 4 +- src/Controls/src/Core/VisualElement.cs | 1 - .../src/Xaml/ApplyPropertiesVisitor.cs | 1 - .../src/Converters/FlexEnumsConverters.cs | 2 +- .../Converters/FlowDirectionTypeConverter.cs} | 12 ++-- src/Core/src/Layouts/FlexEnums.cs | 8 +-- src/Core/src/Primitives/FlowDirection.cs | 5 +- 12 files changed, 103 insertions(+), 91 deletions(-) delete mode 100644 src/Controls/docs/Microsoft.Maui.Controls/FlowDirectionConverter.xml create mode 100644 src/Controls/src/Build.Tasks/CompiledConverters/EnumTypeConverter.cs create mode 100644 src/Controls/src/Build.Tasks/CompiledConverters/FlexBasisTypeConverter.cs rename src/{Controls/src/Core/FlowDirectionConverter.cs => Core/src/Converters/FlowDirectionTypeConverter.cs} (56%) diff --git a/src/Controls/docs/Microsoft.Maui.Controls/FlowDirectionConverter.xml b/src/Controls/docs/Microsoft.Maui.Controls/FlowDirectionConverter.xml deleted file mode 100644 index 27ee65feb080..000000000000 --- a/src/Controls/docs/Microsoft.Maui.Controls/FlowDirectionConverter.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - Microsoft.Maui.Controls.Core - 0.0.0.0 - 2.0.0.0 - - - Microsoft.Maui.Controls.TypeConverter - - - - - Microsoft.Maui.Controls.Xaml.TypeConversion(typeof(Microsoft.Maui.Controls.FlowDirection)) - - - - Converts a string representation of a flow direction to a . - - This converter recognizes and converts string representations of the enumeration, as well as the following strings, regardless of case: "ltr", "rtl", and "inherit". - - - - - - - - Constructor - - Microsoft.Maui.Controls.Core - 0.0.0.0 - 2.0.0.0 - - - - Creates a new default converter. - To be added. - - - - - - - - Method - - Microsoft.Maui.Controls.Core - 0.0.0.0 - 2.0.0.0 - - - System.Object - - - - - - The value to convert. - Returns the object for the string representation. - The object for the string representation. - To be added. - - - - diff --git a/src/Controls/src/Build.Tasks/CompiledConverters/EnumTypeConverter.cs b/src/Controls/src/Build.Tasks/CompiledConverters/EnumTypeConverter.cs new file mode 100644 index 000000000000..59525c4f46da --- /dev/null +++ b/src/Controls/src/Build.Tasks/CompiledConverters/EnumTypeConverter.cs @@ -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 : ICompiledTypeConverter where TEnum: struct + { + public IEnumerable 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)); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Build.Tasks/CompiledConverters/FlexBasisTypeConverter.cs b/src/Controls/src/Build.Tasks/CompiledConverters/FlexBasisTypeConverter.cs new file mode 100644 index 000000000000..8c44a8ab69de --- /dev/null +++ b/src/Controls/src/Build.Tasks/CompiledConverters/FlexBasisTypeConverter.cs @@ -0,0 +1,50 @@ +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 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.Ldc_I4_0); //isRelative: false + yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference(("Microsoft.Maui", "Microsoft.Maui.Layouts", "FlexBasis"), parameterTypes: new[] { + ("mscorlib", "System", "Single"), + ("mscorlib", "System", "Boolean")})); + yield break; + } + } + throw new BuildException(BuildExceptionCode.Conversion, node, null, value, typeof(FlexBasis)); + } + } +} diff --git a/src/Controls/src/Build.Tasks/CompiledConverters/FontSizeTypeConverter.cs b/src/Controls/src/Build.Tasks/CompiledConverters/FontSizeTypeConverter.cs index f22b52ecbc8f..0ea509c80f6a 100644 --- a/src/Controls/src/Build.Tasks/CompiledConverters/FontSizeTypeConverter.cs +++ b/src/Controls/src/Build.Tasks/CompiledConverters/FontSizeTypeConverter.cs @@ -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 @@ -25,7 +23,7 @@ public IEnumerable ConvertFromString(string value, ILContext contex } #pragma warning disable CS0612 // Type or member is obsolete - if (Enum.TryParse(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); diff --git a/src/Controls/src/Build.Tasks/NodeILExtensions.cs b/src/Controls/src/Build.Tasks/NodeILExtensions.cs index 96bcbce0dedb..c66919fa3df0 100644 --- a/src/Controls/src/Build.Tasks/NodeILExtensions.cs +++ b/src/Controls/src/Build.Tasks/NodeILExtensions.cs @@ -155,14 +155,24 @@ static T TryFormat(Func 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) }, + { module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexDirectionTypeConverter")), typeof(EnumTypeConverter) }, + { module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexAlignContentTypeConverter")), typeof(EnumTypeConverter) }, + { module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexAlignItemsTypeConverter")), typeof(EnumTypeConverter) }, + { module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexAlignSelfTypeConverter")), typeof(EnumTypeConverter) }, + { module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexWrapTypeConverter")), typeof(EnumTypeConverter) }, + { module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlexBasisTypeConverter")), typeof(FlexBasisTypeConverter) }, + { module.ImportReference(("Microsoft.Maui", "Microsoft.Maui.Converters", "FlowDirectionTypeConverter")), typeof(EnumTypeConverter) }, + }; } 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); diff --git a/src/Controls/src/Core.Design/AttributeTableBuilder.cs b/src/Controls/src/Core.Design/AttributeTableBuilder.cs index eb105744e50b..c99f8bb1f8a5 100644 --- a/src/Controls/src/Core.Design/AttributeTableBuilder.cs +++ b/src/Controls/src/Core.Design/AttributeTableBuilder.cs @@ -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", @@ -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)); } -} \ No newline at end of file +} diff --git a/src/Controls/src/Core/VisualElement.cs b/src/Controls/src/Core/VisualElement.cs index 5d4fffc03ed8..66e875e3010b 100644 --- a/src/Controls/src/Core/VisualElement.cs +++ b/src/Controls/src/Core/VisualElement.cs @@ -332,7 +332,6 @@ void InvalidateGradientBrushRequested(object sender, EventArgs e) IFlowDirectionController FlowController => this; /// - [System.ComponentModel.TypeConverter(typeof(FlowDirectionConverter))] public FlowDirection FlowDirection { get { return (FlowDirection)GetValue(FlowDirectionProperty); } diff --git a/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs b/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs index c7c6960ff714..68fa95cc53b0 100644 --- a/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs +++ b/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs @@ -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 diff --git a/src/Core/src/Converters/FlexEnumsConverters.cs b/src/Core/src/Converters/FlexEnumsConverters.cs index b7c84e69c40e..5ffec8389665 100644 --- a/src/Core/src/Converters/FlexEnumsConverters.cs +++ b/src/Core/src/Converters/FlexEnumsConverters.cs @@ -218,9 +218,9 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c var strValue = value?.ToString(); if (strValue != null) { + strValue = 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)) diff --git a/src/Controls/src/Core/FlowDirectionConverter.cs b/src/Core/src/Converters/FlowDirectionTypeConverter.cs similarity index 56% rename from src/Controls/src/Core/FlowDirectionConverter.cs rename to src/Core/src/Converters/FlowDirectionTypeConverter.cs index a61ad315698d..7df280d741c8 100644 --- a/src/Controls/src/Core/FlowDirectionConverter.cs +++ b/src/Core/src/Converters/FlowDirectionTypeConverter.cs @@ -2,20 +2,17 @@ using System.ComponentModel; using System.Globalization; -namespace Microsoft.Maui.Controls +#nullable disable +namespace Microsoft.Maui.Converters { - /// - public class FlowDirectionConverter : TypeConverter + public class FlowDirectionTypeConverter : TypeConverter { - /// public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => sourceType == typeof(string); - /// public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) => destinationType == typeof(string); - /// public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { var strValue = value?.ToString(); @@ -32,10 +29,9 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c if (strValue.Equals("inherit", StringComparison.OrdinalIgnoreCase)) return FlowDirection.MatchParent; } - throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", strValue, typeof(FlowDirection))); + throw new InvalidOperationException($"Cannot convert \"{strValue}\" into {typeof(FlowDirection)}"); } - /// public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (value is not FlowDirection direction) diff --git a/src/Core/src/Layouts/FlexEnums.cs b/src/Core/src/Layouts/FlexEnums.cs index 9a23545c6b63..bc8012283f1c 100644 --- a/src/Core/src/Layouts/FlexEnums.cs +++ b/src/Core/src/Layouts/FlexEnums.cs @@ -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) @@ -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); } } \ No newline at end of file diff --git a/src/Core/src/Primitives/FlowDirection.cs b/src/Core/src/Primitives/FlowDirection.cs index 5b883bc9a4c4..917825ecd0eb 100644 --- a/src/Core/src/Primitives/FlowDirection.cs +++ b/src/Core/src/Primitives/FlowDirection.cs @@ -1,6 +1,9 @@ -namespace Microsoft.Maui +using System.ComponentModel; + +namespace Microsoft.Maui { /// + [TypeConverter(typeof(Converters.FlowDirectionTypeConverter))] public enum FlowDirection { ///