From 06d22616f8b6c79363ed46f1aa1e98b37467da91 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Tue, 25 Jul 2023 10:00:46 +0300 Subject: [PATCH] fix: Fix TemplateBinding not working with attached DPs (cherry picked from commit 96e2283611bf21c676ad03e5bb8d6d026c844830) # Conflicts: # src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Given_Binding.cs --- .../XamlGenerator/XamlFileGenerator.cs | 62 ++++++++++--------- .../Binding_TemplateBinding_AttachedDP.xaml | 28 +++++++++ ...Binding_TemplateBinding_AttachedDP.xaml.cs | 28 +++++++++ .../BindingTests/Given_Binding.cs | 26 ++++++++ 4 files changed, 116 insertions(+), 28 deletions(-) create mode 100644 src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Controls/Binding_TemplateBinding_AttachedDP.xaml create mode 100644 src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Controls/Binding_TemplateBinding_AttachedDP.xaml.cs diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs index 6941ee4aa371..d1114dd1fd3c 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs @@ -1783,7 +1783,7 @@ private void BuildInlineStyle(IIndentedStringBuilder writer, XamlObjectDefinitio if (basedOnNode != null) { - writer.AppendLineInvariantIndented("BasedOn = (global::Windows.UI.Xaml.Style){0},", BuildBindingOption(basedOnNode, Generation.StyleSymbol.Value)); + writer.AppendLineInvariantIndented("BasedOn = (global::Windows.UI.Xaml.Style){0},", BuildBindingOption(basedOnNode, Generation.StyleSymbol.Value, isTemplateBindingAttachedProperty: false)); } using (writer.BlockInvariant("Setters = ", fullTargetType)) @@ -1874,7 +1874,7 @@ private void BuildPropertySetter(IIndentedStringBuilder writer, string fullTarge GetGlobalizedTypeName(fullTargetType), property, propertyType, - BuildLiteralValue(valueNode, propertyType) + BuildLiteralValue(valueNode, isTemplateBindingAttachedProperty: false, propertyType) ); } else @@ -1884,7 +1884,7 @@ private void BuildPropertySetter(IIndentedStringBuilder writer, string fullTarge "new global::Windows.UI.Xaml.Setter<{0}>(\"{1}\", o => {3}.{1} = {2})" + lineEnding, GetGlobalizedTypeName(fullTargetType), property, - BuildLiteralValue(valueNode, propertyType), + BuildLiteralValue(valueNode, isTemplateBindingAttachedProperty: false, propertyType), targetInstance ); } @@ -1983,7 +1983,7 @@ private void BuildPropertySetter(IIndentedStringBuilder writer, string fullTarge if (HasMarkupExtension(valueNode)) { TryAnnotateWithGeneratorSource(writer, suffix: isDependencyProperty ? "NonResourceMarkupValueDP" : "MarkupValuePOCO"); - writer.AppendLineIndented(BuildBindingOption(valueNode, propertyType)); + writer.AppendLineIndented(BuildBindingOption(valueNode, propertyType, isTemplateBindingAttachedProperty: false)); } else { @@ -4032,7 +4032,7 @@ private void BuildSetAttachedProperty(IIndentedStringBuilder writer, string clos TryAnnotateWithGeneratorSource(writer); var literalValue = isCustomMarkupExtension ? GetCustomMarkupExtensionValue(member) - : BuildLiteralValue(member, propertyType: propertyType, owner: member, objectUid: objectUid); + : BuildLiteralValue(member, isTemplateBindingAttachedProperty: false, propertyType: propertyType, owner: member, objectUid: objectUid); var memberGlobalizedType = FindType(member.Member.DeclaringType)?.GetFullyQualifiedTypeIncludingGlobal() ?? GetGlobalizedTypeName(member.Member.DeclaringType.Name); writer.AppendLineInvariantIndented( @@ -4152,7 +4152,7 @@ private void BuildComplexPropertyValue(IIndentedStringBuilder writer, XamlMember if (bindingOptions != null) { TryAnnotateWithGeneratorSource(writer, suffix: "HasBindingOptions"); - var isAttachedProperty = IsDependencyProperty(declaringType, member.Member.Name); + var isDependencyProperty = IsDependencyProperty(declaringType, member.Member.Name); var isBindingType = SymbolEqualityComparer.Default.Equals(_metadataHelper.FindPropertyTypeByOwnerSymbol(declaringType, member.Member.Name), Generation.DataBindingSymbol.Value); var isOwnerDependencyObject = member.Owner != null && GetType(member.Owner.Type) is { } ownerType && ( @@ -4160,19 +4160,19 @@ private void BuildComplexPropertyValue(IIndentedStringBuilder writer, XamlMember ownerType.GetAllInterfaces().Any(i => SymbolEqualityComparer.Default.Equals(i, Generation.DependencyObjectSymbol.Value)) ); - if (isAttachedProperty) + if (isDependencyProperty) { var propertyOwner = declaringType; using (writer.Indent($"{prefix}SetBinding(", $"){postfix}")) { writer.AppendLineIndented($"{propertyOwner!.GetFullyQualifiedTypeIncludingGlobal()}.{member.Member.Name}Property,"); - WriteBinding(); + WriteBinding(isTemplateBindingAttachedProperty: templateBindingNode is not null && IsAttachedProperty(declaringType, member.Member.Name)); } } else if (isBindingType) { - WriteBinding(prefix: $"{prefix}{member.Member.Name} = "); + WriteBinding(isTemplateBindingAttachedProperty: false, prefix: $"{prefix}{member.Member.Name} = "); writer.AppendLineIndented(postfix); } else @@ -4182,18 +4182,18 @@ private void BuildComplexPropertyValue(IIndentedStringBuilder writer, XamlMember using (writer.Indent($"{prefix}{pocoBuilder}SetBinding(", $"){postfix}")) { writer.AppendLineIndented($"\"{member.Member.Name}\","); - WriteBinding(); + WriteBinding(isTemplateBindingAttachedProperty: false); } } - void WriteBinding(string? prefix = null) + void WriteBinding(bool isTemplateBindingAttachedProperty, string? prefix = null) { writer.AppendLineIndented($"{prefix}new {XamlConstants.Types.Binding}()"); var containsCustomMarkup = bindingOptions.Any(x => IsCustomMarkupExtensionType(x.Objects.FirstOrDefault()?.Type)); var closure = containsCustomMarkup ? "___b" : default; var setters = bindingOptions - .Select(x => BuildMemberPropertyValue(x, closure)) + .Select(x => BuildMemberPropertyValue(x, isTemplateBindingAttachedProperty, closure)) .Concat(additionalOptions ?? Array.Empty()) .Where(x => !string.IsNullOrEmpty(x)) .ToArray(); @@ -4587,7 +4587,7 @@ private string RewriteNamespaces(string xamlString) private string GetDefaultBindMode() => _currentDefaultBindMode.Peek(); - private string BuildMemberPropertyValue(XamlMemberDefinition m, string? closure = null) + private string BuildMemberPropertyValue(XamlMemberDefinition m, bool isTemplateBindingAttachedProperty, string? closure = null) { if (IsCustomMarkupExtensionType(m.Objects.FirstOrDefault()?.Type)) { @@ -4599,7 +4599,7 @@ private string BuildMemberPropertyValue(XamlMemberDefinition m, string? closure { return "{0} = {1}".InvariantCultureFormat( m.Member.Name == "_PositionalParameters" ? "Path" : m.Member.Name, - BuildBindingOption(m, FindPropertyType(m.Member))); + BuildBindingOption(m, FindPropertyType(m.Member), isTemplateBindingAttachedProperty)); } } @@ -4633,7 +4633,7 @@ private string GetCustomMarkupExtensionValue(XamlMemberDefinition member, string { var propertyType = markupType.GetPropertyWithName(m.Member.Name)?.Type as INamedTypeSymbol; var resourceName = GetSimpleStaticResourceRetrieval(m, propertyType); - var value = resourceName ?? BuildLiteralValue(m, propertyType: propertyType, owner: member); + var value = resourceName ?? BuildLiteralValue(m, isTemplateBindingAttachedProperty: false, propertyType: propertyType, owner: member); return "{0} = {1}".InvariantCultureFormat(m.Member.Name, value); }) @@ -4792,7 +4792,7 @@ private INamedTypeSymbol FindUnderlyingType(INamedTypeSymbol propertyType) return (propertyType.IsNullable(out var underlyingType) && underlyingType is INamedTypeSymbol underlyingNamedType) ? underlyingNamedType : propertyType; } - private string BuildLiteralValue(INamedTypeSymbol propertyType, string? memberValue, XamlMemberDefinition? owner = null, string memberName = "", string objectUid = "") + private string BuildLiteralValue(INamedTypeSymbol propertyType, bool isTemplateBindingAttachedProperty, string? memberValue, XamlMemberDefinition? owner = null, string memberName = "", string objectUid = "") { var literalValue = Inner(); TryAnnotateWithGeneratorSource(ref literalValue); @@ -5000,7 +5000,14 @@ string Inner() || propertyType.SpecialType == SpecialType.System_Object ) { - return "@\"" + memberValue?.ToString() + "\""; + if (isTemplateBindingAttachedProperty) + { + return "@\"(" + memberValue + ")\""; + } + else + { + return "@\"" + memberValue + "\""; + } } if (memberValue == null && propertyType.IsReferenceType) @@ -5151,7 +5158,7 @@ private static string BuildGridLength(string memberValue) return $"new global::{XamlConstants.Types.GridLength}({gridLength.Value.ToStringInvariant()}f, global::{XamlConstants.Types.GridUnitType}.{gridLength.GridUnitType})"; } - private string BuildLiteralValue(XamlMemberDefinition member, INamedTypeSymbol? propertyType = null, XamlMemberDefinition? owner = null, string objectUid = "") + private string BuildLiteralValue(XamlMemberDefinition member, bool isTemplateBindingAttachedProperty, INamedTypeSymbol? propertyType = null, XamlMemberDefinition? owner = null, string objectUid = "") { var literal = Inner(); TryAnnotateWithGeneratorSource(ref literal); @@ -5172,7 +5179,7 @@ string Inner() if (propertyType != null) { - var s = BuildLiteralValue(propertyType, memberValue, owner ?? member, member.Member.Name, objectUid); + var s = BuildLiteralValue(propertyType, isTemplateBindingAttachedProperty, memberValue, owner ?? member, member.Member.Name, objectUid); return s; } else @@ -5292,7 +5299,7 @@ private string BuildColor(string memberValue) } } - private string BuildBindingOption(XamlMemberDefinition m, INamedTypeSymbol? propertyType) + private string BuildBindingOption(XamlMemberDefinition m, INamedTypeSymbol? propertyType, bool isTemplateBindingAttachedProperty) { // The default member is Path var isPositionalParameter = m.Member.Name == "_PositionalParameters"; @@ -5372,9 +5379,8 @@ private string BuildBindingOption(XamlMemberDefinition m, INamedTypeSymbol? prop if (memberName == "Path") { - var value = BuildLiteralValue(m, GetPropertyTypeByOwnerSymbol(Generation.DataBindingSymbol.Value, memberName)); + var value = BuildLiteralValue(m, isTemplateBindingAttachedProperty, GetPropertyTypeByOwnerSymbol(Generation.DataBindingSymbol.Value, memberName)); value = RewriteAttachedPropertyPath(value); - return value; } else if (memberName == "ElementName") @@ -5439,7 +5445,7 @@ private string BuildBindingOption(XamlMemberDefinition m, INamedTypeSymbol? prop } } - var value = BuildLiteralValue(m, targetValueType); + var value = BuildLiteralValue(m, isTemplateBindingAttachedProperty: false, targetValueType); value = explicitCast + value; return value; @@ -5587,7 +5593,7 @@ Func propertyPredicate { if (FindPropertyType(member.Member) != null) { - writer.AppendLineInvariantIndented("{0} = {1}{2}", fullValueSetter, BuildLiteralValue(member, objectUid: objectUid ?? ""), closingPunctuation); + writer.AppendLineInvariantIndented("{0} = {1}{2}", fullValueSetter, BuildLiteralValue(member, isTemplateBindingAttachedProperty: false, objectUid: objectUid ?? ""), closingPunctuation); } else { @@ -5923,7 +5929,7 @@ private void BuildChild(IIndentedStringBuilder writer, XamlMemberDefinition? own if (property != null) { - var value = BuildLiteralValue(valueNode); + var value = BuildLiteralValue(valueNode, isTemplateBindingAttachedProperty: false); // This builds property setters for the owner of the setter. writer.AppendLineIndented($"new Windows.UI.Xaml.Setter(new Windows.UI.Xaml.TargetPropertyPath(this, \"{property}\"), {value})"); @@ -5952,7 +5958,7 @@ private void BuildChild(IIndentedStringBuilder writer, XamlMemberDefinition? own if (valueNode.Objects.None()) { - string value = BuildLiteralValue(valueNode); + string value = BuildLiteralValue(valueNode, isTemplateBindingAttachedProperty: false); writer.AppendLineIndented(value + ")"); } else @@ -6015,7 +6021,7 @@ private void BuildChild(IIndentedStringBuilder writer, XamlMemberDefinition? own throw new InvalidOperationException($"Unable to find content value on {xamlObjectDefinition}"); } - writer.AppendIndented(BuildLiteralValue(implicitContent, knownType, owner)); + writer.AppendIndented(BuildLiteralValue(implicitContent, isTemplateBindingAttachedProperty: false, knownType, owner)); } else { @@ -6408,7 +6414,7 @@ private IEnumerable EnumerateSubElements(IEnumerable + + + + + + + + diff --git a/src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Controls/Binding_TemplateBinding_AttachedDP.xaml.cs b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Controls/Binding_TemplateBinding_AttachedDP.xaml.cs new file mode 100644 index 000000000000..c445a4450a55 --- /dev/null +++ b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Controls/Binding_TemplateBinding_AttachedDP.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 + +namespace Uno.UI.Tests.Windows_UI_Xaml_Data.BindingTests.Controls; +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +public sealed partial class Binding_TemplateBinding_AttachedDP : Page +{ + public Binding_TemplateBinding_AttachedDP() + { + this.InitializeComponent(); + } +} diff --git a/src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Given_Binding.cs b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Given_Binding.cs index 6f915a2f5522..f6896b746e45 100644 --- a/src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Given_Binding.cs +++ b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/BindingTests/Given_Binding.cs @@ -198,5 +198,31 @@ public void When_Xaml_Object_With_Xaml_Object_Properties() binding.RelativeSource.Mode.Should().Be(RelativeSourceMode.None); binding.Source.Should().Be("Source"); } +<<<<<<< HEAD +======= + + [TestMethod] + public void When_Binding_Empty_Quotes() + { + var SUT = new Binding_Empty_Quotes(); + SUT.ForceLoaded(); + SUT.sut.Text.Should().Be("Current DataContext: MyDataContext"); + } + + [TestMethod] + public void When_TemplateBinding_Attached_Property() + { + var SUT = new Binding_TemplateBinding_AttachedDP(); + SUT.ForceLoaded(); + var tb = SUT.tb; + var sv = (ScrollViewer)tb.GetTemplateRoot(); + + Assert.AreEqual(ScrollBarVisibility.Auto, sv.HorizontalScrollBarVisibility); + Assert.AreEqual(ScrollBarVisibility.Hidden, sv.VerticalScrollBarVisibility); + + Assert.AreEqual(ScrollBarVisibility.Auto, (ScrollBarVisibility)tb.GetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty)); + Assert.AreEqual(ScrollBarVisibility.Hidden, (ScrollBarVisibility)tb.GetValue(ScrollViewer.VerticalScrollBarVisibilityProperty)); + } +>>>>>>> 96e2283611 (fix: Fix TemplateBinding not working with attached DPs) } }