Will Will - 1 month ago 8
C# Question

Why am I getting an "Items Collection Must Be Empty" exception with nested DataGrids?

I'm using nested DataGrids to manage classes with nested class collections.

Each nested class is represented by a cell template.

This is a minimal mockup which reproduces the issue :

using System.ComponentModel;
using System.Linq;

namespace ICMBE{
public class Outer : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;

private Nested1[ ] _categories = Enumerable.Range( 1, 1
).Select( n => new Nested1( ) ).ToArray( );

public Nested1[ ] Categories {
get { return this._categories; }
}
}

public class Nested1 : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;

private Nested2[ ] _questions = Enumerable.Range( 1, 5
).Select( n => new Nested2( ) ).ToArray( );

public Nested2[ ] Questions {
get { return this._questions; }
}
}

public class Nested2 : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;

private Nested3[] _answers = Enumerable.Range( 1, 5
).Select( n => new Nested3( ) ).ToArray( );

public Nested3[ ] Answers {
get { return this._answers; }
}
}

public class Nested3 : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;

private string _foo = "Bar";

public string Foo { get { return this._foo; } }
}
}


Create a field value and expose it in the application :

using System.ComponentModel;

namespace IMCBE{
public partial class App : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private Outer _outer = new Outer( );
}
}

namespace IMCBE{
public partial class Program {
/// <summary>
/// Bla bla bla
/// </summary>
public Outer Outer{
get { return this._outer; }
}
}
}


Using this window -

<Window
x:Class="ICMBE.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:WPFTools.Controls;assembly=WPFTools"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WhyAreMyRowNumbersChanging"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<!-- Answers -->
<DataTemplate x:Key="dtAnswerTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="5" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ToggleButton>
<Viewbox>
<TextBlock Text="Correct" />
</Viewbox>
</ToggleButton>
<TextBox Text="Bar" />
</Grid>
</DataTemplate>

<!-- Questions -->
<DataTemplate x:Key="dtQuestionTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="5" />
<RowDefinition Height="25" />
<RowDefinition Height="5" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="128" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="128" />
<ColumnDefinition Width="5" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Viewbox Grid.ColumnSpan="3">
<TextBlock Text="Question" />
</Viewbox>
<TextBox Grid.Row="2" Grid.ColumnSpan="3" Text="Foo" />
<ToggleButton Grid.Row="4">
<Viewbox>
<TextBlock Text="Bonus" />
</Viewbox>
</ToggleButton>
<Button Grid.Row="4" Grid.Column="2" />
<Viewbox Grid.Column="4">
<TextBlock Text="Answers" />
</Viewbox>
<DataGrid
AutoGenerateColumns="False" CanUserAddRows="False"
CanUserDeleteRows="False" Grid.Column="4"
Grid.RowSpan="4" ItemsSource="{Binding Nested}">
<DataGridTemplateColumn
Width="*"
CellTemplate="{StaticResource dtAnswerTemplate}" />
</DataGrid>
</Grid>
</DataTemplate>

<!-- Categories -->
<DataTemplate x:Key="dtCategoryTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="256" />
<ColumnDefinition Width="5" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Viewbox>
<TextBlock Text="Outer"/>
</Viewbox>
<DataGrid
AutoGenerateColumns="False" CanUserAddRows="False"
CanUserDeleteRows="False" Grid.Row="2"
Grid.ColumnSpan="3" HeadersVisibility="None"
ItemsSource="{Binding Nested}">
<DataGrid.Columns>
<DataGridTemplateColumn
Width="*"
CellTemplate="{StaticResource dtQuestionTemplate}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</DataTemplate>
</Window.Resources>
<DataGrid
Grid.Row="1"
ItemsSource="{Binding Outer.Nested, Source={x:Static Application.Current}}"
MaxHeight="Infinity" ScrollViewer.CanContentScroll="True">
<DataGrid.Columns>
<DataGridTemplateColumn
Width="*" CellTemplate="{StaticResource dtCategoryTemplate}" />
</DataGrid.Columns>
</DataGrid>
</Window>


Running this causes the program to just crash. The exception is "Items collection must be empty".

From what I've read, this happens if you set the
Items
and
ItemsSource
are both set, but this isn't happening here.

Why is this crash occurring?

Answer

From what I've read, this happens if you set the Items and ItemsSource are both set.

This is actually the cause of the error, because you forgot to put a <DataGrid.Columns> tag around the DataGridTemplateColumn in the DataGrid in the dtQuestionTemplate DataTemplate.

It should look like this:

<DataGrid ... ItemsSource="{Binding Nested}">
    <DataGrid.Columns>
        <DataGridTemplateColumn
            Width="*" CellTemplate="{StaticResource dtAnswerTemplate}" />
    </DataGrid.Columns>
</DataGrid>