microsoft-ui-xaml icon indicating copy to clipboard operation
microsoft-ui-xaml copied to clipboard

Binding with ElementName doesn't work from within a TreeViewItem

Open weitzhandler opened this issue 8 months ago • 7 comments

Describe the bug

When using a Binding with ElementName from within a TreeViewItem in a DataTemplate, the binding is not resolved and no binding errors are reported.

Steps to reproduce the bug

<Window
    x:Class="App10.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App10"
    x:Name="window">

    <TreeView ItemsSource="{x:Bind ViewModels}">
        <TreeView.ItemTemplate>
            <DataTemplate x:DataType="local:Entity">
                <TreeViewItem ItemsSource="{x:Bind Children}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{x:Bind Name}" />
                        <TextBlock Text="{Binding StuffProcessor.StuffTitle, ElementName=window}" />
                    </StackPanel>
                </TreeViewItem>
            </DataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</Window>
using Microsoft.UI.Xaml;
using System.Collections.Generic;

namespace App10;

public sealed partial class MainWindow : Window
{
    public MainWindow() =>
        InitializeComponent();

    public List<Entity> ViewModels { get; } =
    [
        new("Parent 1")
        {
            Children=
            [
                new("Child 1.1"),
                new("Child 1.2"),
                new("Child 1.3"),
            ]
        },
        new("Parent 2")
        {
            Children=
            [
                new("Child 2.1"),
                new("Child 2.2"),
                new("Child 2.3"),
            ]
        },
    ];

    public string Annotation => "Annotation";
}

public class Entity(string name)
{
    public string Name { get; } = name;

    public List<Entity> Children { get; set; } = [];
}

Actual behavior

Image

Expected behavior

Annotation property should be accessed and materialized.

Image

Screenshots

No response

NuGet package version

WinUI 3 - Windows App SDK 1.7.0: 1.7.250310001

Windows version

Windows 11 (22H2): Build 22621

Additional context

No response

weitzhandler avatar Mar 26 '25 16:03 weitzhandler

Dup? https://github.com/microsoft/microsoft-ui-xaml/issues/2508 https://github.com/microsoft/microsoft-ui-xaml/issues/560

ghost1372 avatar Mar 26 '25 17:03 ghost1372

Not sure it's the same issue but it's definitely related. That issue has been around for 6 years! Binding with ElementName is a crucial and very common functionality in any XAML app. Not fixing or addressing an issue of this nature is neglect and disrespect.

weitzhandler avatar Mar 27 '25 09:03 weitzhandler

Binding != x:Bind so not the same issue as #2508, but can confirm that this is indeed an issue. Possibly related to #560.

I thought maybe this has to do with the weirdness that is Window in WinUI (it's not really a full-class XAML element citizen the same way as other elements like Page/UserControl, it's more a simple wrapper over a native window). I usually just new one up in code at startup and drop a Frame or Page into it and keep all the real code inside other controls to avoid some problems. That said, I tried this, and it also did not work:

<Page x:Class="TestUno.MainPage"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Background="{ThemeResource BackgroundBrush}"
     x:Name="page">
    <ScrollViewer x:Name="sv" Tag="Annotation">
        <TreeView ItemsSource="{x:Bind ViewModels}">
            <TreeView.ItemTemplate>
                <DataTemplate x:DataType="local:Entity">
                    <TreeViewItem ItemsSource="{x:Bind Children}">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{x:Bind Name}" />
                            <TextBlock Text="{Binding Tag, ElementName=sv}" />
                        </StackPanel>
                    </TreeViewItem>
                </DataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </ScrollViewer>
</Page>

Also tried Text="{Binding Annotation, ElementName=page}" and neither works. Output window does not show any binding errors.

mikernet avatar Mar 28 '25 14:03 mikernet

@weitzhandler As with other such similar situations, generally the answer as to how to handle this situation currently is to bind to objects that have everything they need accessible from them so you don't need to bind outside of the template.

mikernet avatar Mar 28 '25 15:03 mikernet

generally the answer as to how to handle this situation currently is to bind to objects that have everything they need accessible from them so you don't need to bind outside of the template

Of course, and I understand that. But that is not always ideal. And in any case WinUI Binding should not break so many things that worked in WPF, especially not in a non-documented way.

This remains a bug that needs to be fixed.

weitzhandler avatar Mar 29 '25 22:03 weitzhandler

generally the answer as to how to handle this situation currently is to bind to objects that have everything they need accessible from them so you don't need to bind outside of the template

Of course, and I understand that. But that is not always ideal. And in any case WinUI Binding should not break so many things that worked in WPF, especially not in a non-documented way.

This remains a bug that needs to be fixed.

Hi Weit, I see your comment in Microsoft "For some odd reason after declaring the template as a static resource with a key and referencing it from the control the issue is gone." can you provide an example?


        <DataTemplate x:Key="MyTemplate">
            <TextBlock Text="{Binding ElementName=ThisPage, Path=viewmodel.Name, Mode=OneWay}" />
        </DataTemplate>


                <TextBlock
                    x:Name="Title"
                    Style="{StaticResource TitleLargeTextBlockStyle}"
                    Text="{x:Bind viewmodel.Name, Mode=OneWay}" />
                <ContentControl ContentTemplate="{StaticResource MyTemplate}" />

I tried this but the ContentControl give me the binding error

Severity	Count	Data Context	Binding Path	Target	Target Type	Description	File	Line	Project
Error	1	power_companies.Features.Campaign.Detail.Page	viewmodel.Name	Microsoft.UI.Xaml.Controls.TextBlock.Text	String	BindingExpression path error: 'viewmodel' property not found on 'power_companies.Features.Campaign.Detail.Page'			

when the textblock above render out the Name just fine

Strypper avatar May 19 '25 04:05 Strypper

I should mention that if you want a workaround, you can use Uno's AncestorBinding markup extension.

mikernet avatar May 20 '25 03:05 mikernet