csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
5.1 KiB
107 lines
5.1 KiB
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using XamlX.Ast;
|
|
using XamlX.Emit;
|
|
using XamlX.IL;
|
|
using XamlX.Transform;
|
|
using XamlX.TypeSystem;
|
|
|
|
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
|
|
{
|
|
using XamlParseException = XamlX.XamlParseException;
|
|
class AvaloniaXamlIlSetterTransformer : IXamlAstTransformer
|
|
{
|
|
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
|
|
{
|
|
if (!(node is XamlAstObjectNode on
|
|
&& on.Type.GetClrType().FullName == "Avalonia.Styling.Setter"))
|
|
return node;
|
|
|
|
var targetTypeNode = context.ParentNodes()
|
|
.OfType<AvaloniaXamlIlTargetTypeMetadataNode>()
|
|
.FirstOrDefault(x => x.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style) ??
|
|
throw new XamlParseException("Can not find parent Style Selector or ControlTemplate TargetType", node);
|
|
|
|
IXamlType propType = null;
|
|
var property = @on.Children.OfType<XamlAstXamlPropertyValueNode>()
|
|
.FirstOrDefault(x => x.Property.GetClrProperty().Name == "Property");
|
|
if (property != null)
|
|
{
|
|
var propertyName = property.Values.OfType<XamlAstTextNode>().FirstOrDefault()?.Text;
|
|
if (propertyName == null)
|
|
throw new XamlParseException("Setter.Property must be a string", node);
|
|
|
|
|
|
var avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName,
|
|
new XamlAstClrTypeReference(targetTypeNode, targetTypeNode.TargetType.GetClrType(), false), property.Values[0]);
|
|
property.Values = new List<IXamlAstValueNode> {avaloniaPropertyNode};
|
|
propType = avaloniaPropertyNode.AvaloniaPropertyType;
|
|
}
|
|
else
|
|
{
|
|
var propertyPath = on.Children.OfType<XamlAstXamlPropertyValueNode>()
|
|
.FirstOrDefault(x => x.Property.GetClrProperty().Name == "PropertyPath");
|
|
if (propertyPath == null)
|
|
throw new XamlX.XamlParseException("Setter without a property or property path is not valid", node);
|
|
if (propertyPath.Values[0] is IXamlIlPropertyPathNode ppn
|
|
&& ppn.PropertyType != null)
|
|
propType = ppn.PropertyType;
|
|
else
|
|
throw new XamlX.XamlParseException("Unable to get the property path property type", node);
|
|
}
|
|
|
|
var valueProperty = on.Children
|
|
.OfType<XamlAstXamlPropertyValueNode>().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value");
|
|
if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlAstTextNode)
|
|
{
|
|
if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0],
|
|
propType, out var converted))
|
|
throw new XamlParseException(
|
|
$"Unable to convert property value to {propType.GetFqn()}",
|
|
valueProperty.Values[0]);
|
|
|
|
valueProperty.Property = new SetterValueProperty(valueProperty.Property,
|
|
on.Type.GetClrType(), propType, context.GetAvaloniaTypes());
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
class SetterValueProperty : XamlAstClrProperty
|
|
{
|
|
public SetterValueProperty(IXamlLineInfo line, IXamlType setterType, IXamlType targetType,
|
|
AvaloniaXamlIlWellKnownTypes types)
|
|
: base(line, "Value", setterType, null)
|
|
{
|
|
Getter = setterType.Methods.First(m => m.Name == "get_Value");
|
|
var method = setterType.Methods.First(m => m.Name == "set_Value");
|
|
Setters.Add(new XamlIlDirectCallPropertySetter(method, types.IBinding));
|
|
Setters.Add(new XamlIlDirectCallPropertySetter(method, types.UnsetValueType));
|
|
Setters.Add(new XamlIlDirectCallPropertySetter(method, targetType));
|
|
}
|
|
|
|
class XamlIlDirectCallPropertySetter : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter>
|
|
{
|
|
private readonly IXamlMethod _method;
|
|
private readonly IXamlType _type;
|
|
public IXamlType TargetType { get; }
|
|
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters();
|
|
public IReadOnlyList<IXamlType> Parameters { get; }
|
|
public void Emit(IXamlILEmitter codegen)
|
|
{
|
|
if (_type.IsValueType)
|
|
codegen.Box(_type);
|
|
codegen.EmitCall(_method, true);
|
|
}
|
|
|
|
public XamlIlDirectCallPropertySetter(IXamlMethod method, IXamlType type)
|
|
{
|
|
_method = method;
|
|
_type = type;
|
|
Parameters = new[] {type};
|
|
TargetType = method.ThisOrFirstParameter();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|