Browse Source

Fix compiled binding with TemplatedParent relative source

pull/8466/head
Max Katz 4 years ago
parent
commit
2619ab1759
  1. 6
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  2. 25
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs
  3. 1
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
  4. 30
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

6
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@ -45,10 +45,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
new AvaloniaXamlIlReorderClassesPropertiesTransformer()
);
InsertBefore<ContentConvertTransformer>(
new AvaloniaXamlIlBindingPathParser(),
InsertBefore<ContentConvertTransformer>(
new AvaloniaXamlIlSelectorTransformer(),
new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(),
new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(),
new AvaloniaXamlIlBindingPathParser(),
new AvaloniaXamlIlPropertyPathTransformer(),
new AvaloniaXamlIlSetterTransformer(),
new AvaloniaXamlIlConstructorServiceProviderTransformer(),

25
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs

@ -121,11 +121,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
throw new XamlParseException("Only one of ElementName, Source, or RelativeSource specified as a binding source. Only one property is allowed.", binding);
}
var mode = relativeSourceObject.Children
var modeProperty = relativeSourceObject.Children
.OfType<XamlAstXamlPropertyValueNode>()
.FirstOrDefault(x => x.Property.GetClrProperty().Name == "Mode")
?.Values[0] is XamlAstTextNode modeAssignedValue ? modeAssignedValue.Text : null;
.FirstOrDefault(x => x.Property.GetClrProperty().Name == "Mode")?
.Values.FirstOrDefault() as XamlAstTextNode
?? relativeSourceObject.Arguments.OfType<XamlAstTextNode>().FirstOrDefault();
var mode = modeProperty?.Text;
if (relativeSourceObject.Arguments.Count == 0 && mode == null)
{
mode = "FindAncestor";
@ -212,16 +215,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
}
else if (mode == "TemplatedParent")
{
var parentType = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>()
var contentTemplateNode = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>()
.FirstOrDefault(x =>
x.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.ControlTemplate)
?.TargetType.GetClrType();
if (parentType is null)
x.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.ControlTemplate);
if (contentTemplateNode is null)
{
throw new XamlParseException("A binding with a TemplatedParent RelativeSource has to be in a ControlTemplate.", binding);
}
var parentType = contentTemplateNode.TargetType.GetClrType();
if (parentType is null)
{
throw new XamlParseException("TargetType has to be set on ControlTemplate.", binding);
}
convertedNode = new TemplatedParentBindingExpressionNode { Type = parentType };
}
else

1
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs

@ -244,6 +244,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
case TemplatedParentBindingExpressionNode templatedParent:
var templatedParentField = context.GetAvaloniaTypes().StyledElement.GetAllFields()
.FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == "TemplatedParentProperty");
nodes.Add(new SelfPathElementNode(selfType));
nodes.Add(new XamlIlAvaloniaPropertyPropertyPathElementNode(
templatedParentField,
templatedParent.Type));

30
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@ -3,8 +3,8 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reactive.Subjects;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
@ -17,8 +17,6 @@ using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.UnitTests;
using JetBrains.Annotations;
using XamlX;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
@ -676,6 +674,32 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
}
[Fact]
public void ResolvesRelativeSourceBindingFromTemplate()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<ContentControl xmlns='https://github.com/avaloniaui'
Content='Hello'>
<ContentControl.Styles>
<Style Selector='ContentControl'>
<Setter Property='Template'>
<ControlTemplate>
<ContentPresenter Content='{CompiledBinding Content, RelativeSource={RelativeSource TemplatedParent}}' />
</ControlTemplate>
</Setter>
</Style>
</ContentControl.Styles>
</ContentControl>";
var contentControl = AvaloniaRuntimeXamlLoader.Parse<ContentControl>(xaml);
contentControl.Measure(new Size(10, 10));
var result = contentControl.GetTemplateChildren().OfType<ContentPresenter>().First();
Assert.Equal("Hello", result.Content);
}
}
[Fact]
public void ResolvesElementNameInTemplate()

Loading…
Cancel
Save