question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

BUG: WinUI3 x:Bind in GridView

See original GitHub issue

Describe the bug Using {x:Bind} on a DependencyPropery inside a Control which is used in the ItemTemplate of a GridView doesn’t work. It shows the FallBackValue and not the correct property. If you change the ItemsPanel of the GridView to a StackPanel it works ok. Normal {Binding} also works ok.

In the following example I have two GridViews. One without an ItemsPanel, the second one with a StackPanel. The GridViews ItemSource is databound to a List of Employee (Name/Salary) objects. The ItemTemplate contains a UserControl (EmployeeControl) which has an Employee DependencyProperty. This property is set using x:Bind.

<Window
    x:Class="ProblemDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ProblemDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Padding="8">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <GridView ItemsSource="{x:Bind Employees}">
            <GridView.ItemTemplate>
                <DataTemplate x:DataType="local:Employee">
                    <local:EmployeesControl Background="Red"
                                            Employee="{x:Bind}" />
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>

        <GridView ItemsSource="{x:Bind Employees}"
                  Grid.Row="1">
            <GridView.ItemTemplate>
                <DataTemplate x:DataType="local:Employee">
                    <local:EmployeesControl Background="Blue"
                                            Employee="{x:Bind}" />
                </DataTemplate>
            </GridView.ItemTemplate>
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
        </GridView>
    </Grid>
</Window>
using Microsoft.UI.Xaml;
using System.Collections.Generic;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace ProblemDemo {
    /// <summary>
    /// An empty window that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainWindow : Window {

        internal List<Employee> Employees = new() {
            new("Fons", 2000),
            new("Ellen", 5000),
            new("Jim", 3000),
        };

        public MainWindow() {
            this.InitializeComponent();
        }
      
    }

    public class Employee {
        public Employee(string name, double salary) {
            this.Name = name;
            this.Salary = salary;
        }

        public string Name { get; set; }
        public double Salary { get; set; }
    }
}

The EmployeeControl has a StackPanel with 2 TextBlock controls in it. The TextBlock Text is databound using x:Bind to the Name and Salary. It also has a ‘dummy’ FallbackValue.

<UserControl x:Class="ProblemDemo.EmployeesControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="using:ProblemDemo"
             RequestedTheme="Dark"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d">

    <StackPanel Background="{x:Bind Background}"
                Spacing="8"
                Padding="8">
        <TextBlock Text="{x:Bind Employee.Name, FallbackValue=NameFallBack}"
                   FontWeight="Bold" />
        <TextBlock Text="{x:Bind Employee.Salary, FallbackValue=0}" />
    </StackPanel>
</UserControl>
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace ProblemDemo {
    public sealed partial class EmployeesControl : UserControl {
        public EmployeesControl() {
            this.InitializeComponent();
        }

        public Employee Employee {
            get => (Employee)GetValue(EmployeeProperty);
            set => SetValue(EmployeeProperty, value);
        }

        public static readonly DependencyProperty EmployeeProperty = DependencyProperty.Register(nameof(Employee), typeof(Employee), typeof(EmployeesControl), new PropertyMetadata(default));
       
    }
}

When you run the code you will see that the first GridView (Red) is showing the FallbackValue. This is the BUG. The second one (Blue) works ok. This is becuase it has the StackPanel in the ItemsPanel. It will stop working you change it to an ItemsStackPanel or ItemsWrapGrid.

Steps to reproduce the bug

Steps to reproduce the behavior:

  1. Clone the repository.
  2. Open the Solution
  3. Run the app

Expected behavior The Red StackPanels should show the correct Name and Salary of all employees. Just like the blue ones do.

Screenshots image

Version Info

NuGet package version: [WinUI 3 - Windows App SDK 0.8: 0.8.2] [WinUI 3 - Windows App SDK 1.0: 1.0.0-experimental1] [WinUI 3 - Windows App SDK 1.0: 1.0.0-preview1]

Windows app type:

UWP Win32
Yes
Windows version Saw the problem?
Insider Build (xxxxx)
May 2021 Update (19043) Yes
October 2020 Update (19042)
May 2020 Update (19041)
November 2019 Update (18363)
May 2019 Update (18362)
October 2018 Update (17763)
April 2018 Update (17134)
Fall Creators Update (16299)
Creators Update (15063)
Device form factor Saw the problem?
Desktop Yes
Xbox
Surface Hub
IoT

Additional context

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
RealTommyKleincommented, Sep 23, 2021

This looks like a bug with ItemsStackPanel, causing x:Binds to be evaluated in an incorrect order. As a workaround, the x:Binds in EmployeeControls.xaml should use Mode=OneWay.

x:Bind’s logic is initially evaluated when the content in its scope is fully initialized. When x:Bind is used with data root of a control or page, it uses the root’s FrameworkElement.Loading to determine when to run. When x:Bind is used in a template, it instead uses the template root’s FrameworkElement.DataContextChanged event, or the framework can directly run the x:Bind logic by invoking IDataTemplateComponent.ProcessBindings or IDataTemplateTemplateExtensions.ProcessBindings.

In the working case with non-ItemsStackPanel roots in GridView.ItemsPanel, the events looks like this:

  1. GridView’s template instances instantiate the EmployeeControl control and sets its Background property
  2. The x:Bind logic for GridView’s template instance runs as a result of DataContextChanged firing, setting the EmployeeControl.Employee property
  3. EmployeeControl’s x:Bind logic (setting its TextBlocks text to Employee fields) runs as a result of a Loading event

In the non-working case with ItemsStackPanel as the GridView.ItemsPanel (which is its default value):

  1. GridView’s template instances instantiate the EmployeeControl control and sets its Background property
  2. EmployeeControl’s x:Bind logic (setting its TextBlocks text to Employee fields) runs as a result of a Loading event. However, EmployeeControl.Employee hasn’t been set yet, so the x:Binds evaluate to incorrect values.
  3. The x:Bind logic for GridView’s template instance runs as a result of a ProcessBindings call from the framework, setting the EmployeeControl.Employee property

I made a repro here (link will only work for MSFT folks). @stephenlpeters can you redirect to someone on the controls team who is more familiar with ItemsStackPanel? It may have something to do with when ItemsStackPanel calls Measure for its template instances (Measure is what would trigger the FrameworkElement.Loading event and cause x:Bind’s logic to run).

0reactions
github-actions[bot]commented, Jul 29, 2023

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 5 days.

Read more comments on GitHub >

github_iconTop Results From Across the Web

x:Bind in WinUI3 Binding to a datetime
A workaround that I used is to put the TextBlock into a UserControl instead of directly putting the TextBlock into the DataTemplate ....
Read more >
Data binding in depth - UWP applications
This topic is about data binding for the APIs that reside in the Windows.UI.Xaml.Data namespace. Data binding is a way for your app's...
Read more >
[UWP] Bug with x:bind with String.Format and two items
Hi I'm getting a compiler error when I try to use x:Bind with string.format and two items: Invalid binding path 'sys:String.
Read more >
Uno Support for x:Bind
Uno supports the x:Bind WinUI feature, which gives the ability to: bind to normal fields and properties; static classes fields; functions with multiple ......
Read more >
Using the Windows Community Toolkit DataGrid with WinUI 3 ...
In this article we demonstrate the Windows Community Toolkit DataGrid in a desktop application powered by the Windows App SDK and a Sqlite ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found