Skip to content

Commit

Permalink
fix: Fix TemplateBinding not working with attached DPs
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Jul 28, 2023
1 parent fb7a486 commit 96e2283
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1671,7 +1671,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))
Expand Down Expand Up @@ -1762,7 +1762,7 @@ private void BuildPropertySetter(IIndentedStringBuilder writer, string fullTarge
GetGlobalizedTypeName(fullTargetType),
property,
propertyType,
BuildLiteralValue(valueNode, propertyType)
BuildLiteralValue(valueNode, isTemplateBindingAttachedProperty: false, propertyType)
);
}
else
Expand All @@ -1772,7 +1772,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
);
}
Expand Down Expand Up @@ -1871,7 +1871,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
{
Expand Down Expand Up @@ -3923,7 +3923,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(
Expand Down Expand Up @@ -4043,27 +4043,27 @@ 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 &&
(
(_xamlTypeToXamlTypeBaseMap.TryGetValue(ownerType, out var baseTypeSymbol) && FindType(baseTypeSymbol)?.GetAllInterfaces().Any(i => SymbolEqualityComparer.Default.Equals(i, Generation.DependencyObjectSymbol.Value)) == true) ||
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
Expand All @@ -4073,18 +4073,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<string>())
.Where(x => !string.IsNullOrEmpty(x))
.ToArray();
Expand Down Expand Up @@ -4478,7 +4478,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))
{
Expand All @@ -4490,7 +4490,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));
}
}

Expand Down Expand Up @@ -4524,7 +4524,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);
})
Expand Down Expand Up @@ -4683,7 +4683,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);
Expand Down Expand Up @@ -4891,7 +4891,14 @@ string Inner()
|| propertyType.SpecialType == SpecialType.System_Object
)
{
return "@\"" + memberValue?.ToString() + "\"";
if (isTemplateBindingAttachedProperty)
{
return "@\"(" + memberValue + ")\"";
}
else
{
return "@\"" + memberValue + "\"";
}
}

if (memberValue == null && propertyType.IsReferenceType)
Expand Down Expand Up @@ -5042,7 +5049,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);
Expand All @@ -5063,7 +5070,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
Expand Down Expand Up @@ -5182,7 +5189,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";
Expand Down Expand Up @@ -5262,9 +5269,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")
Expand Down Expand Up @@ -5329,7 +5335,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;
Expand Down Expand Up @@ -5477,7 +5483,7 @@ Func<XamlMemberDefinition, bool> 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
{
Expand Down Expand Up @@ -5813,7 +5819,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})");
Expand Down Expand Up @@ -5842,7 +5848,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
Expand Down Expand Up @@ -5905,7 +5911,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
{
Expand Down Expand Up @@ -6298,7 +6304,7 @@ private IEnumerable<XamlObjectDefinition> EnumerateSubElements(IEnumerable<XamlO
innerWriter.AppendLineInvariantIndented(
"{0}.Visibility = {1};",
closureName,
BuildLiteralValue(visibilityMember)
BuildLiteralValue(visibilityMember, isTemplateBindingAttachedProperty: false)
);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Page
x:Class="Uno.UI.Tests.Windows_UI_Xaml_Data.BindingTests.Controls.Binding_TemplateBinding_AttachedDP"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.UI.Tests.Windows_UI_Xaml_Data.BindingTests.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<Page.Resources>
<Style x:Key="MyStyle" TargetType="TextBox">
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<ScrollViewer VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<StackPanel>
<TextBox Style="{StaticResource MyStyle}" x:Name="tb" x:FieldModifier="public" />
</StackPanel>
</Page>
Original file line number Diff line number Diff line change
@@ -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;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class Binding_TemplateBinding_AttachedDP : Page
{
public Binding_TemplateBinding_AttachedDP()
{
this.InitializeComponent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -206,5 +206,20 @@ public void When_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));
}
}
}

0 comments on commit 96e2283

Please sign in to comment.