简体   繁体   English

在 ViewModel 中修改 ObservableCollection 时绑定到 ObservableCollection 的 DataGrid MultiSelect 不稳定

[英]DataGrid MultiSelect bound to ObservableCollection unstable when ObservableCollection is modified in the ViewModel

I'm building a WPF C# application that has multiple DataGrids bound to their respective ObservableCollections that contain objects.我正在构建一个 WPF C# 应用程序,该应用程序有多个DataGrids绑定到它们各自包含对象的ObservableCollections

I will focus on the DataGrid that binds to the Conduits ObservableCollection to keep things simple.我将专注于绑定到Conduits ObservableCollectionDataGrid以保持简单。

The DataGrids are set to multi select SelectionMode="Extended" . DataGrids设置为多 select SelectionMode="Extended" The data in the DataGrids is also represented in a 2D view via a Canvas and drawing elements. DataGrids中的数据也通过Canvas和绘图元素在 2D 视图中表示。

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.这个想法是用户可以 select 2D 或DataGrids中的对象,作为单个项目,或多个项目/行,并且DataGrid行或 object 在 2D 将突出显示。

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.DataGrid ViewModels尚未初始化时,我可以毫无问题地删除 2D 中的对象。 Once they are initialized I get the following error when deleting in 2D.初始化它们后,在 2D 中删除时会出现以下错误。

`System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'`

Objects are deleted in 2D as follows:对象在 2D 中被删除,如下所示:

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:关联的DataGrid绑定到对象,选中对象如下:

<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这是 Conduit DataGridsObservableCollection和所选 Conduit 的列表

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:为了让DataGrids将多个选定的行绑定到SelectedConduitList ,使用了自定义datagrid ,如下所示:

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?有谁知道为什么我不能从我的 2D 布局ViewModel中修改(例如删除)一个 object 形式的SelectedConduitList而不会在初始化DataGrid ViewModels后引发错误?

The exception message means that you cannot remove an item from an IEnumerable while enumerating it using a foreach loop.异常消息意味着您无法在使用foreach循环枚举IEnumerable时将其删除。

The general solution is to replace the foreach loop with a for loop and iterate through the collection backwards:一般的解决方案是用for循环替换foreach循环并向后迭代集合:

for (int i = SelectedConduitList.Count - 1; i >= 0; i--)
{
    Conduit conduit = SelectedConduitList[i] as Conduit;
    if (conduit != null)
        Conduits.Remove(conduit);
}

Please refer to this blog post for more information.请参阅博客文章了解更多信息。

I can delete objects in the 2D without problem when the DataGrid ViewModels have not been initialized.当 DataGrid ViewModel 尚未初始化时,我可以毫无问题地删除 2D 中的对象。 Once they are initialized I get the following error when deleting in 2D.初始化它们后,在 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.从附加源的集合中删除会导致从选定元素的集合中删除,在该集合上您有一个 foreach 循环。 Changing the foreach source while it is running is not allowed.不允许在运行时更改 foreach 源。
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);
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM