I’m building a WPF C# application that has multiple DataGrids
bound to their respective ObservableCollections
that contain objects.
I will focus on the DataGrid
that binds to the Conduits
ObservableCollection
to keep things simple.
The DataGrids
are set to multi select SelectionMode="Extended"
.
The data in the DataGrids
is also represented in a 2D view via a Canvas
and drawing elements.
The idea is the user can select the objects in 2D or the DataGrids
, as a single item, or multiple items/rows, and the DataGrid
row, or object in 2D will be highlighted.
This is producing some unstable results. Too many to list, so I will focus on deleting items. I can delete objects in the 2D without problem when the DataGrid
ViewModels
have not been initialized. Once they are initialized I get the following error when deleting in 2D.
`System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'`
Objects are deleted in 2D as follows:
foreach (object _conduit in SelectedConduitList)
{
if (_conduit is Conduit conduit)
{
Conduits.Remove(conduit);
}
}
The associated DataGrid
is bound to the objects, and selected objects as follows:
<custom:ConduitDataGrid
ItemsSource="{Binding Path=NetworkMain.Conduits}"
SelectionMode="Extended"
SelectedItemsList="{Binding NetworkMain.SelectedConduitList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
Here is the ObservableCollection
for the Conduit DataGrids
and the list for the selected Conduits
public ObservableCollection<Conduit> Conduits { get; set; } = new();
private IList _selectedConduitList = new ArrayList();
public IList SelectedConduitList
{
get { return _selectedConduitList; }
set
{
_selectedConduitList = value;
//changes the IsSelected property of all objects in the ObserbservableCollection to false
DeselectAll();
//changes the IsSelected property of all objects in the ObserbservableCollection to true if the object exists in the SelectedConduitList
SelectConduits();
NotifyOfPropertyChange(nameof(SelectedConduitList));
}
}
In order to get the DataGrids
to bind multiple selected rows to the SelectedConduitList
a custom datagrid
was used as follows:
public class ConduitDataGrid : DataGrid
{
public ConduitDataGrid()
{
this.SelectionChanged += CustomDataGrid_SelectionChanged;
}
void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.SelectedItemsList = this.SelectedItems;
}
#region SelectedItemsList
public IList SelectedItemsList
{
get { return (IList)GetValue(SelectedItemsListProperty); }
set
{
SetValue(SelectedItemsListProperty, value);
}
}
public static readonly DependencyProperty SelectedItemsListProperty =
DependencyProperty.Register(nameof(SelectedItemsList), typeof(IList), typeof(ConduitDataGrid), new PropertyMetadata(null));
#endregion
}
Does anybody know why I can’t modify (for example delete) an object form the SelectedConduitList
from within my 2D Layout ViewModel
without throwing an error once the DataGrid ViewModels
have been initialised?
I can delete objects in the 2D without problem when the DataGrid ViewModels have not been initialized. Once they are initialized I get the following error when deleting in 2D.
Deleting from the collection to which the source is attached leads to the deletion from the collection of selected elements, on which you have a foreach loop.
Changing the foreach source while it is running is not allowed.
This is a common problem and the simplest solution is to make a copy of the list and then loop over it.
foreach (Conduit conduit in SelectedConduitList.OfType<Conduit>().ToList())
{
Conduits.Remove(conduit);
}