Repository: AvaloniaUI/Avalonia
File: src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplatePartsChecker.cs (C#)

Code before:
            if (attr.Type.Name == "TemplatePartAttribute")
            {
                if (!attr.Properties.TryGetValue("Name", out var nameObj))
                {
                    nameObj = attr.Parameters.FirstOrDefault();
                }

                if (!attr.Properties.TryGetValue("Type", out var typeObj))
                {
                    typeObj = attr.Parameters.Skip(1).FirstOrDefault();
                }

                attr.Properties.TryGetValue("IsRequired", out var isRequiredObj);

                if (nameObj is string { Length :> 0 } name
                    && !dictionary.ContainsKey(name))
                {
                    dictionary.Add(name, (typeObj as IXamlType, isRequiredObj as bool? == true));
                }
            }
        }

        return dictionary;
    }

    private class TemplatePartVisitor : Dictionary<string, (IXamlType type, IXamlLineInfo line)>, IXamlAstVisitor
    {
        IXamlAstNode IXamlAstVisitor.Visit(IXamlAstNode node)
        {
            if (node is not XamlAstObjectNode objectNode)
                return node;

            var clrType = objectNode.Type.GetClrType();

            foreach (var child in objectNode.Children)
            {
                if (child is XamlAstXamlPropertyValueNode propertyValueNode &&
                    propertyValueNode.Property is XamlIlAvaloniaProperty namedProperty &&
                    namedProperty.Name == "Name" &&
                    propertyValueNode.Values.Count > 0 &&
                    propertyValueNode.Values[0] is XamlAstTextNode text)
                {
                    this[text.Text] = (clrType, text);
                }
            }

            return node;
        }

        void IXamlAstVisitor.Push(IXamlAstNode node) { }


Review comment (suggestion):
Consider the following XAML:

```xml
<StackPanel>
    <ContentPresenter x:Name="PART_ContentPresenterWithTypo"/>
    <ItemsControl>
       <ItemsControl.ItemTemplate>
       ...
           <ContentPresenter x:Name="PART_ContentPresenter" />
       ...
       </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>
```

Would it be handled correctly? Right now the visitor can find an x:Name from a non-root scope.

Code after:
            if (attr.Type.Name == "TemplatePartAttribute")
            {
                if (!attr.Properties.TryGetValue("Name", out var nameObj))
                {
                    nameObj = attr.Parameters.FirstOrDefault();
                }

                if (!attr.Properties.TryGetValue("Type", out var typeObj))
                {
                    typeObj = attr.Parameters.Skip(1).FirstOrDefault();
                }

                attr.Properties.TryGetValue("IsRequired", out var isRequiredObj);

                if (nameObj is string { Length :> 0 } name
                    && !dictionary.ContainsKey(name))
                {
                    dictionary.Add(name, (typeObj as IXamlType, isRequiredObj as bool? == true));
                }
            }
        }

        return dictionary;
    }

    private class TemplatePartVisitor : Dictionary<string, (IXamlType type, IXamlLineInfo line)>, IXamlAstVisitor
    {
        private int _metadataScopeLevel = 0;
        private Stack<IXamlAstNode> _parents = new();
        
        IXamlAstNode IXamlAstVisitor.Visit(IXamlAstNode node)
        {
            if (_metadataScopeLevel == 1
                && node is AvaloniaNameScopeRegistrationXamlIlNode nameScopeRegistration
                && nameScopeRegistration.Name is XamlAstTextNode textNode)
            {
                this[textNode.Text] = (nameScopeRegistration.TargetType, textNode);
            }

            return node;
        }

        void IXamlAstVisitor.Push(IXamlAstNode node)
        {
            _parents.Push(node);
            if (node is NestedScopeMetadataNode)
            {
                _metadataScopeLevel++;
            }
        }