Skip to content

Instantly share code, notes, and snippets.

@paulpatarinski
Last active August 29, 2015 14:17
Show Gist options
  • Save paulpatarinski/776d899c36f0b6fdf3d0 to your computer and use it in GitHub Desktop.
Save paulpatarinski/776d899c36f0b6fdf3d0 to your computer and use it in GitHub Desktop.
Xamarin Forms Xaml

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment