Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ElementName bindings deeper in ItemsRepeater.ItemTemplate don't work #9715

Closed
Naveen61097 opened this issue Jun 11, 2024 · 8 comments
Closed
Labels
area-Binding area-ItemsRepeater bug Something isn't working closed-Fixed Described behavior has been fixed. fix-released The fix has been in a release (experimental, preview, stable, or servicing). team-Controls Issue for the Controls team
Milestone

Comments

@Naveen61097
Copy link

          Still Facing this Issue on Windows App SDK v1.5.240404000

Originally posted by @AathifMahir in #560 (comment)

@microsoft-github-policy-service microsoft-github-policy-service bot added the needs-triage Issue needs to be triaged by the area owners label Jun 11, 2024
@Naveen61097
Copy link
Author

#560 (comment)

@codendone codendone added bug Something isn't working area-ItemsRepeater area-Binding team-Controls Issue for the Controls team and removed needs-triage Issue needs to be triaged by the area owners labels Jun 13, 2024
@Naveen61097
Copy link
Author

Naveen61097 commented Jun 20, 2024

Upon checking the issue in the latest version (1.5.240607001) I have identified that the ElementName binding is working fine for the very first Element inside the DataTemplate. But using the ElementName binding inside its Children/Content, it breaks.

Here is the sample code, with issue and also a workaround solution,

<Grid Margin="0,100,0,0" ColumnSpacing="100">

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    
    <StackPanel Grid.Column="0">
        <TextBlock Text="TextBlock located directly inside DataTemplate"
                   Height="100"
                   TextWrapping="Wrap" />

        <ItemsRepeater ItemsSource="{x:Bind Users}">
            <ItemsRepeater.ItemTemplate>
                <DataTemplate x:DataType="x:String">
                    <TextBlock Text="{Binding ViewModel.SampleText, ElementName=RootControl, Mode=OneWay}" />
                </DataTemplate>
            </ItemsRepeater.ItemTemplate>
        </ItemsRepeater>
    </StackPanel>

    <StackPanel Grid.Column="1">
        <TextBlock Text="TextBlock not located directly inside DataTemplate"
                   Height="100"
                   TextWrapping="Wrap" />

        <ItemsRepeater ItemsSource="{x:Bind Users}">
            <ItemsRepeater.ItemTemplate>
                <DataTemplate x:DataType="x:String">
                    <StackPanel>
                        <TextBlock Text="{Binding ViewModel.SampleText, ElementName=RootControl, Mode=OneWay}" />
                    </StackPanel>
                </DataTemplate>
            </ItemsRepeater.ItemTemplate>
        </ItemsRepeater>
    </StackPanel>

    <StackPanel Grid.Column="2">
        <TextBlock Text="TextBlock not located directly inside DataTemplate - Workaround"
                   Height="100"
                   TextWrapping="Wrap" />

        <ItemsRepeater ItemsSource="{x:Bind Users}">
            <ItemsRepeater.ItemTemplate>
                <DataTemplate x:DataType="x:String">
                    <StackPanel x:Name="RootPanel"
                                Loaded="RootPanel_Loaded">
                        <TextBlock Text="{Binding Tag.ViewModel.SampleText, ElementName=RootPanel, Mode=OneWay}" />
                    </StackPanel>
                </DataTemplate>
            </ItemsRepeater.ItemTemplate>
        </ItemsRepeater>
    </StackPanel>

</Grid>
public sealed partial class UserControl1 : UserControl
{
    public List<string> Users { get; set; } = [];

    public InvoiceViewModel ViewModel { get; set; } = new InvoiceViewModel()
    {
        SampleText = "Test String"
    };

    public UserControl1()
    {
        for (int i = 0; i < 10; i++)
        {
            Users.Add(i.ToString());
        }

        this.InitializeComponent();
        this.DataContext = this;
    }

    private void RootPanel_Loaded(object sender, RoutedEventArgs e)
    {
        (sender as FrameworkElement).Tag = this;
    }
}

public class InvoiceViewModel
{
    public string SampleText { get; set; }
}

Output:

image

As a workaround, On the Loaded event of the very first element, I have assigned the this object to its Tag property and used it to get the ViewModel object inside the DataTemplate.

As we have migrated all the existing ListView controls to ItemsRepeater and ItemsView, this is a showstopper issue for us. Provide the fix ASAP and also your input on proceeding with the above workaround.

@codendone

@Naveen61097
Copy link
Author

@michael-hawker @AndrewKeepCoding your thoughts on the workaround please.

@michael-hawker
Copy link
Collaborator

Surprised this would have regressed between releases. Related to #2508 which would be having x:Bind properly work in these scenarios to begin with. FYI @evelynwu-msft.

@Naveen61097
Copy link
Author

Related to #2508, In my case, the ViewModel object will be passed to the Xaml UserControl through Constructor or Dependency Property i.e through code-behind. In such cases I cannot assign x:Name for it, hence the x: Bind is not working.

@AndrewKeepCoding
Copy link
Contributor

@Naveen61097 AFAIK, the fix addressed in v1.5 never fixed this issue. Can you share a reproducible project of your case?

@ranjeshj
Copy link
Contributor

I created a simpler repro to show the problem. ElementName bindings at root work as expected now, but nested inside don't seem to.

 <StackPanel>
     <TextBlock Text="Hello" x:Name="MyTextBlock1"/>
     <TextBlock Text="World" x:Name="MyTextBlock2"/>
     <ItemsRepeater x:Name="repeater1">
         <ItemsRepeater.ItemTemplate>
             <DataTemplate>
                 <TextBlock Text="{Binding Text, ElementName=MyTextBlock1, Mode=OneWay}" />
             </DataTemplate>
         </ItemsRepeater.ItemTemplate>
     </ItemsRepeater>

     <ItemsRepeater x:Name="repeater2">
         <ItemsRepeater.ItemTemplate>
             <DataTemplate>
                 <StackPanel>
                     <TextBlock Text="{Binding Text, ElementName=MyTextBlock2, Mode=OneWay}" />
                 </StackPanel>
             </DataTemplate>
         </ItemsRepeater.ItemTemplate>
     </ItemsRepeater>
 </StackPanel>

 repeater1.ItemsSource = repeater2.ItemsSource = Enumerable.Range(0, 5);

@ranjeshj ranjeshj changed the title ElementName bindings don't work inside ItemsRepeater DataTemplate ElementName bindings deeper in ItemsRepeater.ItemTemplate don't work Jun 28, 2024
@ranjeshj
Copy link
Contributor

One potential simpler workaround than the loaded event would be to bind to root of the template and bind again like so (not ideal but should work)

  <ItemsRepeater x:Name="repeater2">
      <ItemsRepeater.ItemTemplate>
          <DataTemplate>
              <StackPanel x:Name="mystack" Tag="{Binding Text, ElementName=MyTextBlock2, Mode=OneWay}">
                  <TextBlock Text="{Binding Tag, ElementName=mystack, Mode=OneWay}" />
              </StackPanel>
          </DataTemplate>
      </ItemsRepeater.ItemTemplate>
  </ItemsRepeater>

@llongley llongley added the closed-Fixed Described behavior has been fixed. label Jul 13, 2024
@codendone codendone added this to the WinAppSDK 1.6 milestone Jul 16, 2024
@codendone codendone added the fix-released The fix has been in a release (experimental, preview, stable, or servicing). label Aug 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Binding area-ItemsRepeater bug Something isn't working closed-Fixed Described behavior has been fixed. fix-released The fix has been in a release (experimental, preview, stable, or servicing). team-Controls Issue for the Controls team
Projects
None yet
Development

No branches or pull requests

6 participants