浏览代码

Fix Relative Source with {x:Type} bindings

Max Katz 2 年之前
父节点
当前提交
29d92f75dc

+ 14 - 13
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<XamlAstXamlPropertyValueNode>()
                         .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")
                     {

+ 60 - 2
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 = @"
+<Window xmlns='https://github.com/avaloniaui'
+        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+        xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
+        x:DataType='local:TestDataContext'
+        Title='test'>
+    <TextBlock Text='{CompiledBinding Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}' x:Name='text'/>
+</Window>";
+                var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+                var target = window.FindControl<TextBlock>("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
 <local:AssignBindingControl xmlns='https://github.com/avaloniaui'
         xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
         xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
-        X='{Binding StringProperty, DataType=local:TestDataContext}' />";
+        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 = @"
+<Window xmlns='https://github.com/avaloniaui'
+        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+        xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
+        x:DataType='local:TestDataContext'
+        x:CompileBindings='True'>
+    <ComboBox x:Name='comboBox' Items='{Binding GenericProperty}' SelectedItem='{Binding GenericProperty.CurrentItem}' />
+</Window>";
+                var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+                var comboBox = window.FindControl<ComboBox>("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<int> GenericProperty { get; } = new();
+        
         public class NonIntegerIndexer : NotifyingBase, INonIntegerIndexerDerived
         {
             private readonly Dictionary<string, string> _storage = new Dictionary<string, string>();
@@ -1858,6 +1911,11 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
         }
     }
 
+    public class ListItemCollectionView<T> : List<T>
+    {
+        public T CurrentItem { get; set; }
+    }
+    
     public class MethodDataContext
     {
         public void Action() { }