Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are relative bindings in a virtualized data grid sometimes not resolved?

Tags:

c#

wpf

I am occasionally getting binding errors from an element in a cell of a data grid. The problematic binding has a relative source. The appearance of the error seems to be dependent on the number columns and on virtualization.

I've recreated a similar problem in a simplfied project. (It's a bit contrived, but it demonstrates the problem.)

Here is the window when it first opens: Here is the window when it first opens

Here is the window when it is resized (note the blank cells): Here is the window when it is resized.  Note the blank cells.

Here is the xaml:

<Window x:Class="Test.DataGridVirtualizationBindingTest"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:test="clr-namespace:Test"
        Title="DataGridVirtualizationBindingTest" Height="300" Width="300">

    <Window.Resources>
        <DataTemplate x:Key="IsReadyTemplate">
            <TextBox 
                Text="{Binding Path=DataContext.IsReady, RelativeSource={RelativeSource AncestorType={x:Type test:DataGridVirtualizationBindingTest}}}"
                />
        </DataTemplate>

    </Window.Resources>
    <Grid>
        <DataGrid 
            ItemsSource="{Binding Records}"
            AutoGenerateColumns="False"
            ScrollViewer.IsDeferredScrollingEnabled="True"
            VirtualizingPanel.IsVirtualizingWhenGrouping="True"
            VirtualizingPanel.VirtualizationMode="Recycling"
            EnableRowVirtualization="True"
            EnableColumnVirtualization="True"
            >

            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
                <DataGridTemplateColumn Header="Ready" CellTemplate="{StaticResource IsReadyTemplate}"/>
            </DataGrid.Columns>
        </DataGrid>

    </Grid>
</Window>

The window's data context is an instance of this class:

class DataGridVirtualizationBindingTestVm 
{
    public DataGridVirtualizationBindingTestVm()
    {
        Records = new ObservableCollection<Record>(Enumerable.Range(1, 4000).Select(i => new Record { Field1 = i.ToString() }));

        IsReady = true;
    }

    public ObservableCollection<Record> Records { get; private set; }

    public bool IsReady { get; set; }
}

public class Record 
{
    public string Field1 { get; set; }
}

The error is

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Test.DataGridVirtualizationBindingTest', AncestorLevel='1''. BindingExpression:Path=DataContext.IsReady; DataItem=null; target element is 'TextBox' (Name=''); target property is 'Text' (type 'String')

It doesn't occur for every cell. The framework is 4.5.2.

Why is the binding sometimes not resolved?

like image 414
Watsontap Avatar asked Aug 31 '25 17:08

Watsontap


1 Answers

Simply remove

EnableColumnVirtualization="True"

Normally you don't need that (only if you have dozens of columns shown at once, but this is not something good for user experience - having long horizontal scroll) and it seems to be the case of the problem.

like image 94
Sinatr Avatar answered Sep 02 '25 06:09

Sinatr