public static bool CustomValueConverter(AstTransformationContext context, IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result) { if (type.FullName == "System.TimeSpan" && node is XamlAstTextNode tn && !tn.Text.Contains(":")) { var seconds = double.Parse(tn.Text, CultureInfo.InvariantCulture); result = new XamlStaticOrTargetedReturnMethodCallNode(tn, type.FindMethod("FromSeconds", type, false, context.Configuration.WellKnownTypes.Double), new[] { new XamlConstantNode(tn, context.Configuration.WellKnownTypes.Double, seconds) }); return(true); } if (type.FullName == "Avalonia.AvaloniaProperty") { var scope = context.ParentNodes().OfType <AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault(); if (scope == null) { throw new XamlX.XamlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node); } if (!(node is XamlAstTextNode text)) { throw new XamlX.XamlLoadException("Property should be a text node", node); } result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text); return(true); } result = null; return(false); }
public static bool CustomValueConverter(AstTransformationContext context, IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result) { if (!(node is XamlAstTextNode textNode)) { result = null; return(false); } var text = textNode.Text; var types = context.GetAvaloniaTypes(); if (type.FullName == "System.TimeSpan") { var tsText = text.Trim(); if (!TimeSpan.TryParse(tsText, CultureInfo.InvariantCulture, out var timeSpan)) { // // shorthand seconds format (ie. "0.25") if (!tsText.Contains(":") && double.TryParse(tsText, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var seconds)) { timeSpan = TimeSpan.FromSeconds(seconds); } else { throw new XamlX.XamlLoadException($"Unable to parse {text} as a time span", node); } } result = new XamlStaticOrTargetedReturnMethodCallNode(node, type.FindMethod("FromTicks", type, false, types.Long), new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) }); return(true); } if (type.Equals(types.FontFamily)) { result = new AvaloniaXamlIlFontFamilyAstNode(types, text, node); return(true); } if (type.FullName == "Avalonia.AvaloniaProperty") { var scope = context.ParentNodes().OfType <AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault(); if (scope == null) { throw new XamlX.XamlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node); } result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text, scope.TargetType, node); return(true); } result = null; return(false); }
public static bool TryConvert(AstTransformationContext context, IXamlAstValueNode node, string text, IXamlType type, AvaloniaXamlIlWellKnownTypes types, out IXamlAstValueNode result) { if (type.FullName == "System.TimeSpan") { var tsText = text.Trim(); if (!TimeSpan.TryParse(tsText, CultureInfo.InvariantCulture, out var timeSpan)) { // // shorthand seconds format (ie. "0.25") if (!tsText.Contains(":") && double.TryParse(tsText, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var seconds)) { timeSpan = TimeSpan.FromSeconds(seconds); } else { throw new XamlX.XamlLoadException($"Unable to parse {text} as a time span", node); } } result = new XamlStaticOrTargetedReturnMethodCallNode(node, type.FindMethod("FromTicks", type, false, types.Long), new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) }); return(true); } if (type.Equals(types.FontFamily)) { result = new AvaloniaXamlIlFontFamilyAstNode(types, text, node); return(true); } if (type.Equals(types.Thickness)) { try { var thickness = Thickness.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Thickness, types.ThicknessFullConstructor, new[] { thickness.Left, thickness.Top, thickness.Right, thickness.Bottom }); return(true); } catch { throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a thickness", node); } } if (type.Equals(types.Point)) { try { var point = Point.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Point, types.PointFullConstructor, new[] { point.X, point.Y }); return(true); } catch { throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a point", node); } } if (type.Equals(types.Vector)) { try { var vector = Vector.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Vector, types.VectorFullConstructor, new[] { vector.X, vector.Y }); return(true); } catch { throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a vector", node); } } if (type.Equals(types.Size)) { try { var size = Size.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Size, types.SizeFullConstructor, new[] { size.Width, size.Height }); return(true); } catch { throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a size", node); } } if (type.Equals(types.Matrix)) { try { var matrix = Matrix.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Matrix, types.MatrixFullConstructor, new[] { matrix.M11, matrix.M12, matrix.M21, matrix.M22, matrix.M31, matrix.M32 }); return(true); } catch { throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a matrix", node); } } if (type.Equals(types.CornerRadius)) { try { var cornerRadius = CornerRadius.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.CornerRadius, types.CornerRadiusFullConstructor, new[] { cornerRadius.TopLeft, cornerRadius.TopRight, cornerRadius.BottomRight, cornerRadius.BottomLeft }); return(true); } catch { throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a corner radius", node); } } if (type.Equals(types.Color)) { if (!Color.TryParse(text, out Color color)) { throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a color", node); } result = new XamlStaticOrTargetedReturnMethodCallNode(node, type.GetMethod( new FindMethodMethodSignature("FromUInt32", type, types.UInt) { IsStatic = true }), new[] { new XamlConstantNode(node, types.UInt, color.ToUint32()) }); return(true); } if (type.Equals(types.GridLength)) { try { var gridLength = GridLength.Parse(text); result = new AvaloniaXamlIlGridLengthAstNode(node, types, gridLength); return(true); } catch { throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a grid length", node); } } if (type.Equals(types.Cursor)) { if (TypeSystemHelpers.TryGetEnumValueNode(types.StandardCursorType, text, node, out var enumConstantNode)) { var cursorTypeRef = new XamlAstClrTypeReference(node, types.Cursor, false); result = new XamlAstNewClrObjectNode(node, cursorTypeRef, types.CursorTypeConstructor, new List <IXamlAstValueNode> { enumConstantNode }); return(true); } } 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 (type.Equals(types.Classes)) { var classes = text.Split(' '); var classNodes = classes.Select(c => new XamlAstTextNode(node, c, types.XamlIlTypes.String)).ToArray(); result = new AvaloniaXamlIlAvaloniaListConstantAstNode(node, types, types.Classes, types.XamlIlTypes.String, classNodes); return(true); } result = null; return(false); }
public static bool CustomValueConverter(AstTransformationContext context, IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result) { if (!(node is XamlAstTextNode textNode)) { result = null; return(false); } var text = textNode.Text; var types = context.GetAvaloniaTypes(); if (type.FullName == "System.TimeSpan") { var tsText = text.Trim(); if (!TimeSpan.TryParse(tsText, CultureInfo.InvariantCulture, out var timeSpan)) { // // shorthand seconds format (ie. "0.25") if (!tsText.Contains(":") && double.TryParse(tsText, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var seconds)) { timeSpan = TimeSpan.FromSeconds(seconds); } else { throw new XamlX.XamlLoadException($"Unable to parse {text} as a time span", node); } } result = new XamlStaticOrTargetedReturnMethodCallNode(node, type.FindMethod("FromTicks", type, false, types.Long), new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) }); return(true); } if (type.Equals(types.FontFamily)) { result = new AvaloniaXamlIlFontFamilyAstNode(types, text, node); return(true); } if (type.Equals(types.Thickness)) { var thickness = Thickness.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Thickness, types.ThicknessFullConstructor, new[] { thickness.Left, thickness.Top, thickness.Right, thickness.Bottom }); return(true); } if (type.Equals(types.Point)) { var point = Point.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Point, types.PointFullConstructor, new[] { point.X, point.Y }); return(true); } if (type.Equals(types.Vector)) { var vector = Vector.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Vector, types.VectorFullConstructor, new[] { vector.X, vector.Y }); return(true); } if (type.Equals(types.Size)) { var size = Size.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Size, types.SizeFullConstructor, new[] { size.Width, size.Height }); return(true); } if (type.Equals(types.Matrix)) { var matrix = Matrix.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Matrix, types.MatrixFullConstructor, new[] { matrix.M11, matrix.M12, matrix.M21, matrix.M22, matrix.M31, matrix.M32 }); return(true); } if (type.Equals(types.CornerRadius)) { var cornerRadius = CornerRadius.Parse(text); result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.CornerRadius, types.CornerRadiusFullConstructor, new[] { cornerRadius.TopLeft, cornerRadius.TopRight, cornerRadius.BottomRight, cornerRadius.BottomLeft }); return(true); } if (type.FullName == "Avalonia.AvaloniaProperty") { var scope = context.ParentNodes().OfType <AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault(); if (scope == null) { throw new XamlX.XamlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node); } result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text, scope.TargetType, node); return(true); } result = null; return(false); }
public static bool TryConvertValue(AstTransformationContext context, IXamlAstValueNode node, IXamlType type, XamlAstClrProperty propertyContext, out IXamlAstValueNode rv) { rv = null; var cfg = context.Configuration; // Since we are doing a conversion anyway, it makes sense to check for the underlying nullable type if (type.GenericTypeDefinition?.Equals(cfg.WellKnownTypes.NullableT) == true) { type = type.GenericArguments[0]; } if (cfg.CustomValueConverter?.Invoke(context, node, type, out rv) == true) { return(true); } var nodeType = node.Type.GetClrType(); // Implicit type converters if (!nodeType.Equals(cfg.WellKnownTypes.String)) { return(false); } if (node is XamlAstTextNode tn) { if (type.IsEnum) { if (TypeSystemHelpers.TryGetEnumValueNode(type, tn.Text, tn, out var enumConstantNode)) { rv = enumConstantNode; return(true); } } // Well known types if (TypeSystemHelpers.ParseConstantIfTypeAllows(tn.Text, type, tn, out var constantNode)) { rv = constantNode; return(true); } if (type.FullName == "System.Type") { var resolvedType = TypeReferenceResolver.ResolveType(context, tn.Text, false, tn, true); rv = new XamlTypeExtensionNode(tn, resolvedType, type); return(true); } if (cfg.WellKnownTypes.Delegate.IsAssignableFrom(type)) { var invoke = type.FindMethod(m => m.Name == "Invoke"); var rootType = context.RootObject.Type.GetClrType(); var handler = rootType.FindMethod(tn.Text, invoke.ReturnType, false, invoke.Parameters.ToArray()); if (handler != null) { rv = new XamlLoadMethodDelegateNode(tn, context.RootObject, type, handler); return(true); } } } IXamlAstValueNode CreateInvariantCulture() => new XamlStaticOrTargetedReturnMethodCallNode(node, cfg.WellKnownTypes.CultureInfo.Methods.First(x => x.IsPublic && x.IsStatic && x.Name == "get_InvariantCulture"), null); var candidates = type.Methods.Where(m => m.Name == "Parse" && m.ReturnType.Equals(type) && m.Parameters.Count > 0 && m.Parameters[0].Equals(cfg.WellKnownTypes.String)).ToList(); // Types with parse method var parser = candidates.FirstOrDefault(m => m.Parameters.Count == 2 && ( m.Parameters[1].Equals(cfg.WellKnownTypes.CultureInfo) || m.Parameters[1].Equals(cfg.WellKnownTypes.IFormatProvider) ) ) ?? candidates.FirstOrDefault(m => m.Parameters.Count == 1); if (parser != null) { var args = new List <IXamlAstValueNode> { node }; if (parser.Parameters.Count == 2) { args.Add(CreateInvariantCulture()); } rv = new XamlStaticOrTargetedReturnMethodCallNode(node, parser, args); return(true); } if (cfg.TypeMappings.TypeDescriptorContext != null) { IXamlType converterType = null; if (propertyContext?.TypeConverters.TryGetValue(type, out converterType) != true) { var typeConverterAttribute = cfg.GetCustomAttribute(type, cfg.TypeMappings.TypeConverterAttributes).FirstOrDefault(); if (typeConverterAttribute != null) { converterType = TryGetTypeConverterFromCustomAttribute(cfg, typeConverterAttribute); } } if (converterType != null) { var converterMethod = converterType.FindMethod("ConvertFrom", cfg.WellKnownTypes.Object, false, cfg.TypeMappings.TypeDescriptorContext, cfg.WellKnownTypes.CultureInfo, cfg.WellKnownTypes.Object); rv = new XamlAstNeedsParentStackValueNode(node, new XamlAstRuntimeCastNode(node, new XamlStaticOrTargetedReturnMethodCallNode(node, converterMethod, new[] { new XamlAstNewClrObjectNode(node, new XamlAstClrTypeReference(node, converterType, false), null, new List <IXamlAstValueNode>()), new XamlAstContextLocalNode(node, cfg.TypeMappings.TypeDescriptorContext), CreateInvariantCulture(), node }), new XamlAstClrTypeReference(node, type, false))); return(true); } } return(false); }