From 523a2bc369faef54cc9ee9449b0916dd71bbf512 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 17 Oct 2023 17:18:45 +0200 Subject: [PATCH] Add compatibility hack for older compiled bindings. Previously, `CompiledBindingPathBuilder` didn't have a `TemplatedParent` method and instead the XAML compiler rewrite templated parent bindings to be a `$self.TemplateParent` property binding. resulting in extraneous logs. Add a constructor with an `apiVersion` to `CompiledBindingPathBuilder` which will be used by newer versions of the XAML compiler, and if a usage is detected using an `apiVersion` of 0, then upgrade `$self.TemplatedParent` to use a `TemplatedParentPathElement`. --- .../XamlIlBindingPathHelper.cs | 8 +++++- .../CompiledBindings/CompiledBindingPath.cs | 25 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs index 8665088a5e..bd8de09a12 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs @@ -900,8 +900,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions public XamlILNodeEmitResult Emit(XamlIlEmitContext context, IXamlILEmitter codeGen) { + var intType = context.Configuration.TypeSystem.GetType("System.Int32"); var types = context.GetAvaloniaTypes(); - codeGen.Newobj(types.CompiledBindingPathBuilder.FindConstructor()); + + // We're calling the CompiledBindingPathBuilder(int apiVersion) with an apiVersion + // of 1 to indicate that we don't want TemplatedParent compatibility hacks enabled. + codeGen + .Ldc_I4(1) + .Newobj(types.CompiledBindingPathBuilder.FindConstructor(new() { intType })); foreach (var transform in _transformElements) { diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs index 338ea70534..0217344ef4 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs @@ -107,9 +107,18 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings public class CompiledBindingPathBuilder { + private readonly int _apiVersion; private object? _rawSource; private readonly List _elements = new(); + public CompiledBindingPathBuilder() + { + } + + // TODO12: Remove this constructor. apiVersion is only needed for compatibility with + // versions of Avalonia which used $self.Property() for building TemplatedParent bindings. + public CompiledBindingPathBuilder(int apiVersion) => _apiVersion = apiVersion; + public CompiledBindingPathBuilder Not() { _elements.Add(new NotExpressionPathElement()); @@ -118,7 +127,21 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings public CompiledBindingPathBuilder Property(IPropertyInfo info, Func, IPropertyInfo, IPropertyAccessor> accessorFactory) { - _elements.Add(new PropertyElement(info, accessorFactory, _elements.Count == 0)); + // Older versions of Avalonia used $self.Property() for building TemplatedParent bindings. + // Try to detect this and upgrade to using a TemplatedParentPathElement so that logging works + // correctly. + if (_apiVersion == 0 && + info.Name == "TemplatedParent" && + _elements.Count >= 1 && + _elements[_elements.Count - 1] is SelfPathElement) + { + _elements.Add(new TemplatedParentPathElement()); + } + else + { + _elements.Add(new PropertyElement(info, accessorFactory, _elements.Count == 0)); + } + return this; }