0
votes

I have got MVVM Applikation. Now i need a Datagrid with a variable amount of columns and rows. Initial populating the datagrid works fine, but the application crashes randomly when updating the datagrid with the following exception

"An unhandled exception occured in the UI: 'Collection was modified; enumeration operation > might not execute.'."

The crash happends directly after calling drawDatagrid()

code in my xaml:

<DataGrid
                            MaxWidth="{Binding Width}"
                            ItemsSource="{Binding SizeQuantityTable}"
                            AutoGenerateColumns="True"
                            SelectionMode="Single"  SelectionUnit="CellOrRowHeader"
                            MouseDown="DataGrid1_MouseClick"
                            MouseDoubleClick="AppointmentOnMouseDoubleClick"
                            CanUserResizeColumns="False"
                            CanUserResizeRows="False"
                            CanUserSortColumns="False"
                            CanUserAddRows="False"
                            CanUserDeleteRows="False"
                            CanUserReorderColumns="False"
                            ScrollViewer.CanContentScroll="True"
                            HorizontalAlignment="Left"
                            VerticalGridLinesBrush="DarkGray"
                            GridLinesVisibility="All"
                            HorizontalGridLinesBrush="DarkGray"

                            />

The Code in the ViewModel for updating the Datagrid

private void drawDataGrid()
    {
        SizeQuantityTable = new DataTable();
        DataColumn dayColumn = new DataColumn();
        try
        {
            dayColumn.ColumnName = "Tag";
            SizeQuantityTable.Columns.Add(dayColumn);
            foreach (var line in CalenderWorkPlanLines)
            {
                DataColumn column = new DataColumn();
                column.ColumnName = line.Fullname;
                SizeQuantityTable.Columns.Add(column);
            }
            for (int i = 0; i < DaysOfMonth.Count(); i++)
            {

                    DataRow row = SizeQuantityTable.NewRow();
                    row[dayColumn] = DaysOfMonth[i];
                    int j = 1;
                    foreach (var line in CalenderWorkPlanLines)
                    {
                        var tmp = line.AppointmentsString.ToList();
                        row[SizeQuantityTable.Columns[j]] = line.AppointmentsString[i];
                        j++;
                    }
                    SizeQuantityTable.Rows.Add(row);
            }

            App.Current.Dispatcher.BeginInvoke(
                        (System.Action)(() =>
                        {
                            RaisePropertyChanged("SizeQuantityTable");

                        }), null);


        }
        catch (Exception ex)
        {
            Loggers.StartUI.Error("Exception during population of SizeQuantityTable - WorkPlanAppointments" + "in CalenderWorkplanViewModel", ex);


        }
    }
1
Is there an update thread that would modify the CalendarWorkPlantLines collection? That modification, especially adds/removed will break the draw call if the draw call is context switched during enumeration. - BradleyDotNET
CalendarWorkPlantLines are modified before every call of drawDataGrid. There is no thread that modifies the CalendarWorkPlantLines collection while executing drawDataGrid. - Arne

1 Answers

0
votes

While I can't see any obvious coding errors in your drawDataGrid method, the Exception that you mentioned is caused because you cannot modify an item from a collection that is being enumerated using the Enumerator class, which is what is used inside a foreach loop.

The fix is simple... once you have found the foreach loop where you are trying to modify the item, you can simply replace the foreach loop with a for loop. Here is a short example:

foreach (Person person in People)
{
    person = anotherPerson; // not allowed
}

Instead of the code above, use the code below:

for (int i = 0; i < People.Count; i++)
{
    People[i] = anotherPerson; // allowed
}