Skip to content

Commit a7aeade

Browse files
[XC] Fix x:DataType resolution for BindingContext (#21454)
* Add test * Add special case for resolving x:DataType for the binding context property
1 parent e2dd6a4 commit a7aeade

File tree

3 files changed

+105
-5
lines changed

3 files changed

+105
-5
lines changed

src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -382,14 +382,26 @@ static IEnumerable<Instruction> CompileBindingPath(ElementNode node, ILContext c
382382

383383
INode dataTypeNode = null;
384384
IElementNode n = node;
385+
386+
// Special handling for BindingContext={Binding ...}
387+
// The order of checks is:
388+
// - x:DataType on the binding itself
389+
// - SKIP looking for x:DataType on the parent
390+
// - continue looking for x:DataType on the parent's parent...
391+
IElementNode skipNode = null;
392+
if (IsBindingContextBinding(node))
393+
{
394+
skipNode = GetParent(node);
395+
}
396+
385397
while (n != null)
386398
{
387-
if (n.Properties.TryGetValue(XmlName.xDataType, out dataTypeNode))
399+
if (n != skipNode && n.Properties.TryGetValue(XmlName.xDataType, out dataTypeNode))
400+
{
388401
break;
389-
if (n.Parent is ListNode listNode)
390-
n = listNode.Parent as IElementNode;
391-
else
392-
n = n.Parent as IElementNode;
402+
}
403+
404+
n = GetParent(n);
393405
}
394406

395407
if (dataTypeNode is null)
@@ -475,6 +487,25 @@ static IEnumerable<Instruction> CompileBindingPath(ElementNode node, ILContext c
475487
yield return Create(Ldnull);
476488
yield return Create(Newobj, module.ImportReference(ctorinforef));
477489
yield return Create(Callvirt, module.ImportPropertySetterReference(context.Cache, bindingExtensionType, propertyName: "TypedBinding"));
490+
491+
static IElementNode GetParent(IElementNode node)
492+
{
493+
return node switch
494+
{
495+
{ Parent: ListNode { Parent: IElementNode parentNode } } => parentNode,
496+
{ Parent: IElementNode parentNode } => parentNode,
497+
_ => null,
498+
};
499+
}
500+
501+
static bool IsBindingContextBinding(ElementNode node)
502+
{
503+
// looking for BindingContext="{Binding ...}"
504+
return GetParent(node) is IElementNode parentNode
505+
&& ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out var propertyName)
506+
&& propertyName.NamespaceURI == ""
507+
&& propertyName.LocalName == nameof(BindableObject.BindingContext);
508+
}
478509
}
479510

480511
static IList<(PropertyDefinition property, TypeReference propDeclTypeRef, string indexArg)> ParsePath(ILContext context, string path, TypeReference tSourceRef, IXmlLineInfo lineInfo, ModuleDefinition module)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System;
2+
using Microsoft.Maui.ApplicationModel;
3+
using Microsoft.Maui.Controls.Core.UnitTests;
4+
using Microsoft.Maui.Dispatching;
5+
6+
using Microsoft.Maui.UnitTests;
7+
using NUnit.Framework;
8+
9+
namespace Microsoft.Maui.Controls.Xaml.UnitTests;
10+
11+
public partial class Maui21434
12+
{
13+
public Maui21434()
14+
{
15+
InitializeComponent();
16+
}
17+
18+
public Maui21434(bool useCompiledXaml)
19+
{
20+
//this stub will be replaced at compile time
21+
}
22+
23+
[TestFixture]
24+
class Test
25+
{
26+
[SetUp]
27+
public void Setup()
28+
{
29+
Application.SetCurrentApplication(new MockApplication());
30+
DispatcherProvider.SetCurrent(new DispatcherProviderStub());
31+
}
32+
33+
[TearDown] public void TearDown() => AppInfo.SetCurrent(null);
34+
35+
[Test]
36+
public void BindingsDoNotResolveStaticProperties([Values(false, true)] bool useCompiledXaml)
37+
{
38+
var page = new Maui21434(useCompiledXaml);
39+
Assert.That(page.ParentTextLabel?.Text, Is.EqualTo("ParentText"));
40+
Assert.That(page.ChildTextLabel?.Text, Is.EqualTo("ChildText"));
41+
}
42+
}
43+
}
44+
45+
public class ParentViewModel21434
46+
{
47+
public string Text => "ParentText";
48+
public ChildViewModel21434 Child { get; } = new();
49+
}
50+
51+
public class ChildViewModel21434
52+
{
53+
public string Text => "ChildText";
54+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
4+
xmlns:local="clr-namespace:Microsoft.Maui.Controls.Xaml.UnitTests"
5+
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.Maui21434"
6+
x:DataType="local:ParentViewModel21434">
7+
<ContentPage.BindingContext>
8+
<local:ParentViewModel21434 />
9+
</ContentPage.BindingContext>
10+
11+
<VerticalStackLayout>
12+
<Label Text="{Binding Text}" x:Name="ParentTextLabel" />
13+
<Label BindingContext="{Binding Child}" Text="{Binding Text}" x:DataType="local:ChildViewModel21434" x:Name="ChildTextLabel" />
14+
</VerticalStackLayout>
15+
</ContentPage>

0 commit comments

Comments
 (0)