是否在迭代中编辑集合

本文关键字:编辑 集合 迭代 是否 | 更新日期: 2023-09-27 18:05:40

前言

我正在构建一个从互联网上抓取一些数据的应用程序。抓取的数据需要实时更新,所以我运行了一个无限循环每次检查以前的页面源是否已更改。所有这些数据都存储在ObservableCollection中,如下所示:

private static ObservableCollection<Models.Event> _allMatches = new ObservableCollection<Models.Event>();
public ObservableCollection<Models.Event> AllMatches
{
    get { return _matches; }
}

ObservableCollectionListView中绑定如下:

<CollectionViewSource Source="{Binding AllMatches}" x:Key="GroupedItems">
    <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="MatchNation" />
        <PropertyGroupDescription PropertyName="MatchLeague" />
    </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

CollectionViewSource帮助我用GroupStyle来组织ListView中的数据,在这种情况下用于Nation -> League

问题开始

我将尝试创建一个简单的示例代码来更好地解释这个问题。因此,每个抓取的数据都与一个事件相匹配,所以我在ObservableCollection中基本上有一个事件列表。

示例代码:

string oldData = null;
List<Event> matchListAll = new List<Event>();
while(true)
{
      string data = new WebClient().DownloadString("websiteLink");
      
      if(data != oldData) //There is an update! Get the new content
      {
            //code for scrape the event
            
            foreach(var item in ItemScraped)
            {
                  Event @event = new Event(); //this will contain the details of event scraped
                  @event.Date = item.Date; //and so on...
                  
                  matchListAll.Add(@event); //Add the event to a list
            }
            
            //when the scraping iteration is over I put all of this event in the ObservableCollection
            AddAllListItem(matchListAll);
      }
}

现在上面的代码非常简单,从互联网上获取事件并将其放入一个对象中,就这样。当抓取完成时,我调用AddAllListItem,这个方法将对ListView中绑定的ObservableCollection进行估价。

这种方法的结构是:

private void AddAllListItem(List<Event> matches)
{
    var allCollection = VM.AllMatches; //Access to AllMatches through the Vm (VM contain the ViewModel instance)
    
    foreach (var @event in matches) //Iterate through the element scraped 
    {
        //Add the scraped element to ObservableCollection so I can see it.
        allCollection.Add(new Event 
        {
            MatchDate = @event.MatchDate,
            ...
        };
    }
}

此代码存在严重问题。我想有人已经知道会发生什么了。

特别是,同时我在ObservableCollection中添加了AddAllListItem方法再次调用,并且我作为参数传递的matches项发生了更改。这将生成一个例外:

集合已修改。枚举操作可能无法执行。

如何解决这种情况

我已经阅读了这里关于这个问题的几个问题,以及其他建议使用.ToList.ToArray的问题,但我有一个ObservableCollection,同时我在屏幕上显示了我也需要更新的元素
我从来没有遇到过这样的情况,我希望有人能帮助我了解解决问题,谢谢。

是否在迭代中编辑集合

也许这会对你有所帮助。

public class AsyncObservableCollection<T> : ObservableCollection<T>
{
    private readonly object lockList = new object();
    public object LockList
    {
        get { return lockList; }
    } 
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        var eh = CollectionChanged;
        if (eh != null)
        {
            Dispatcher dispatcher = (from NotifyCollectionChangedEventHandler nh in eh.GetInvocationList()
                                     let dpo = nh.Target as DispatcherObject
                                     where dpo != null
                                     select dpo.Dispatcher).FirstOrDefault();
            if (dispatcher != null && dispatcher.CheckAccess() == false)
            {
                dispatcher.Invoke(DispatcherPriority.DataBind, (Action)(() => OnCollectionChanged(e)));
            }
            else
            {
                foreach (NotifyCollectionChangedEventHandler nh in eh.GetInvocationList())
                    nh.Invoke(this, e);
            }
        }
    }
    new public void Remove(T item)
    {
        lock (lockList)
        {
            base.Remove(item);
        }
    }
    new public void Add(T item)
    {
        lock (lockList)
        {
            base.Add(item);
        }
    }
    public void AddByCheckExistence(T item)
    {
        lock (lockList)
        {
            if(!this.Contains(item))
            {
                base.Add(item);
            }
        }
    }
}