This gist aims to demystify how Xamarin Forms Xaml works.
Here is the call stack executed to render a Xaml File.
1.LoadFromXaml - BindableObject Extension
2.XamlLoader.Load - uses XmlReader to read the xaml file
using (XmlReader reader = XmlReader.Create((TextReader) new StringReader(xaml)))
{
while (reader.Read())
{
if (reader.NodeType != XmlNodeType.Whitespace && reader.NodeType == XmlNodeType.Element)
{
XamlLoader.RuntimeRootNode runtimeRootNode = new XamlLoader.RuntimeRootNode(new XmlType(reader.NamespaceURI, reader.Name, (IList<XmlType>) null), (object) view);
XamlParser.ParseXaml((RootNode) runtimeRootNode, reader);
HydratationContext context = new HydratationContext()
{
RootElement = view
};
runtimeRootNode.Accept((IXamlNodeVisitor) new XamlNodeVisitor((Action<INode, INode>) ((node, parent) => node.Parent = parent), false), (INode) null);
runtimeRootNode.Accept((IXamlNodeVisitor) new NamescopingVisitor(context), (INode) null);
runtimeRootNode.Accept((IXamlNodeVisitor) new CreateValuesVisitor(context), (INode) null);
runtimeRootNode.Accept((IXamlNodeVisitor) new RegisterXNamesVisitor(context), (INode) null);
runtimeRootNode.Accept((IXamlNodeVisitor) new ParseMarkupsVisitor(context), (INode) null);
runtimeRootNode.Accept((IXamlNodeVisitor) new ApplyPropertiesVisitor(context), (INode) null);
break;
}
}
}
3.XamlParser.ParseXaml
public static void ParseXaml(RootNode rootNode, XmlReader reader)
{
IList<KeyValuePair<XmlName, INode>> list = XamlParser.ParseXamlAttributes(reader);
IDictionaryExtensions.AddRange<XmlName, INode>((IDictionary<XmlName, INode>) rootNode.Properties, (IEnumerable<KeyValuePair<XmlName, INode>>) list);
XamlParser.ParseXamlElementFor((IElementNode) rootNode, reader);
}
4.RootNode.Accept
public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
{
if (!visitor.VisitChildrenFirst)
visitor.Visit(this, parentNode);
foreach (INode node in this.Properties.Values)
node.Accept(visitor, (INode) this);
foreach (INode node in this.CollectionItems)
node.Accept(visitor, (INode) this);
if (!visitor.VisitChildrenFirst)
return;
visitor.Visit(this, parentNode);
}
5.ApplyPropertiesVisitor.Visit
public void Visit(ValueNode node, INode parentNode)
{
IElementNode index = parentNode as IElementNode;
object obj = this.Values[(INode) node];
object xamlelement = this.Values[parentNode];
XmlName name;
if (ApplyPropertiesVisitor.TryGetPropertyName((INode) node, parentNode, out name))
{
if (this.skips.Contains(name))
return;
ApplyPropertiesVisitor.SetPropertyValue(xamlelement, name, obj, this.Context.RootElement, (INode) node, this.Context, (IXmlLineInfo) node);
}
else
{
ContentPropertyAttribute customAttribute;
if (!ApplyPropertiesVisitor.IsCollectionItem((INode) node, parentNode) || !(parentNode is IElementNode) || (customAttribute = CustomAttributeExtensions.GetCustomAttribute<ContentPropertyAttribute>((MemberInfo) IntrospectionExtensions.GetTypeInfo(this.Context.Types[index]))) == null)
return;
XmlName propertyName = new XmlName(((ElementNode) parentNode).NamespaceURI, customAttribute.Name);
if (this.skips.Contains(propertyName))
return;
ApplyPropertiesVisitor.SetPropertyValue(xamlelement, propertyName, obj, this.Context.RootElement, (INode) node, this.Context, (IXmlLineInfo) node);
}
}
The source comes from decompiling Xamarin.Forms.Xaml and may not be 100% accurate