diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs index 6150265cf8..736e764aa7 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs @@ -146,13 +146,23 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Tree") ?.Values[0] is XamlAstTextNode treeTypeValue ? treeTypeValue.Text : "Visual"; - var ancestorTypeName = relativeSourceObject.Children + var ancestorType = relativeSourceObject.Children .OfType() .FirstOrDefault(x => x.Property.GetClrProperty().Name == "AncestorType") - ?.Values[0] as XamlAstTextNode; + ?.Values[0] switch + { + XamlAstTextNode textNode => TypeReferenceResolver.ResolveType( + context, + textNode.Text, + false, + textNode, + true).GetClrType(), + XamlTypeExtensionNode typeExtensionNode => typeExtensionNode.Value.GetClrType(), + null => null, + _ => throw new XamlParseException($"Unsupported node for AncestorType property", relativeSourceObject) + }; - IXamlType ancestorType = null; - if (ancestorTypeName is null) + if (ancestorType is null) { if (treeType == "Visual") { @@ -174,15 +184,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers } } } - else - { - ancestorType = TypeReferenceResolver.ResolveType( - context, - ancestorTypeName.Text, - false, - ancestorTypeName, - true).GetClrType(); - } if (treeType == "Visual") { diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs index 0b33cd9d97..27634b457b 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs @@ -847,6 +847,30 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions Assert.Equal("test", target.Text); } } + + [Fact] + public void ResolvesRelativeSourceBindingEvenLongerForm() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var target = window.FindControl("text"); + + window.ApplyTemplate(); + window.Presenter.ApplyTemplate(); + target.ApplyTemplate(); + + Assert.Equal("test", target.Text); + } + } [Fact] public void ResolvesRelativeSourceBindingFromTemplate() @@ -1735,7 +1759,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions "; + X='{CompiledBinding StringProperty, DataType=local:TestDataContext}' />"; var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(new RuntimeXamlLoaderDocument(xaml), new RuntimeXamlLoaderConfiguration { UseCompiledBindingsByDefault = true }); var compiledPath = ((CompiledBindingExtension)control.X).Path; @@ -1745,6 +1769,33 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions } } + [Fact] + public void Should_Bind_To_Nested_Generic_Property() + { + // See https://github.com/AvaloniaUI/Avalonia/issues/10485 + // This code works fine with SRE, and test is passing, but it fails on Cecil. + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var comboBox = window.FindControl("comboBox"); + + var dataContext = new TestDataContext(); + dataContext.GenericProperty.Add(123); + dataContext.GenericProperty.CurrentItem = 123; + window.DataContext = dataContext; + + Assert.Equal(123, comboBox.SelectedItem); + } + } + static void Throws(string type, Action cb) { try @@ -1837,8 +1888,10 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions public string ExplicitProperty => "Bye"; - public static string StaticProperty => "World"; + public static string StaticProperty => "World"; + public ListItemCollectionView GenericProperty { get; } = new(); + public class NonIntegerIndexer : NotifyingBase, INonIntegerIndexerDerived { private readonly Dictionary _storage = new Dictionary(); @@ -1858,6 +1911,11 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions } } + public class ListItemCollectionView : List + { + public T CurrentItem { get; set; } + } + public class MethodDataContext { public void Action() { }