| File: CompiledValueProviders\SetterValueProvider.cs | Web Access |
| Project: src\src\Controls\src\Build.Tasks\Controls.Build.Tasks.csproj (Microsoft.Maui.Controls.Build.Tasks) |
using System.Collections.Generic; using System.Xml; using Microsoft.Maui.Controls.Build.Tasks; using Microsoft.Maui.Controls.Xaml; using Mono.Cecil; using Mono.Cecil.Cil; namespace Microsoft.Maui.Controls.XamlC { class SetterValueProvider : ICompiledValueProvider { public IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context) { INode valueNode = null; if (!((IElementNode)node).Properties.TryGetValue(new XmlName("", "Value"), out valueNode) && !((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.MauiUri, "Value"), out valueNode) && ((IElementNode)node).CollectionItems.Count == 1) valueNode = ((IElementNode)node).CollectionItems[0]; var bpNode = ((ValueNode)((IElementNode)node).Properties[new XmlName("", "Property")]); var bpRef = (new BindablePropertyConverter()).GetBindablePropertyFieldReference((string)bpNode.Value, context, module, bpNode); if (SetterValueIsCollection(bpRef, module, node, context)) yield break; // valueNode is null, for example, when OnPlatform doesn't have a match for the current platform, so the property should not be set if (valueNode == null) yield break; //if it's an elementNode, there's probably no need to convert it if (valueNode is IElementNode) yield break; var value = ((string)((ValueNode)valueNode).Value); var setterType = ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls", "Setter"); //push the setter foreach (var instruction in vardefref.VariableDefinition.LoadAs(context.Cache, module.GetTypeDefinition(context.Cache, setterType), module)) yield return instruction; //push the value foreach (var instruction in ((ValueNode)valueNode).PushConvertedValue(context, bpRef, (requiredServices) => valueNode.PushServiceProvider(context, requiredServices, bpRef: bpRef), boxValueTypes: true, unboxValueTypes: false)) yield return instruction; //set the value yield return Instruction.Create(OpCodes.Callvirt, module.ImportPropertySetterReference(context.Cache, setterType, propertyName: "Value")); } static bool SetterValueIsCollection(FieldReference bindablePropertyReference, ModuleDefinition module, BaseNode node, ILContext context) { var items = (node as IElementNode)?.CollectionItems; if (items == null || items.Count <= 0) return false; // Is this a generic type ? var generic = bindablePropertyReference.GetBindablePropertyType(context.Cache, node, module) as GenericInstanceType; // With a single generic argument? if (generic?.GenericArguments.Count != 1) return false; // Is the generic argument assignable from this value? var genericType = generic.GenericArguments[0]; if (!(items[0] is IElementNode firstItem)) return false; return context.Variables[firstItem].VariableType.InheritsFromOrImplements(context.Cache, genericType); } } }