2016-09-04 59 views
1

前言在迭代中编辑集合?

我建立从互联网凑一些数据的应用程序。 抓取的数据需要实时更新,所以我运行一个无限循环 ,每次检查以前的页面源是否被更改。 所有这些数据都存储在ObservableCollection里面是这样的:

private static ObservableCollection<Models.Event> _allMatches = new ObservableCollection<Models.Event>(); 

public ObservableCollection<Models.Event> AllMatches 
{ 
    get { return _matches; } 
} 

将此O bservableCollectionListView被绑定如下:

<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为 再次调用,并且我作为参数传递的匹配项目已更改。这将产生 例外:

集合被修改。枚举操作可能不会执行。

如何解决这种情况?

我读过一些问题在这里问这个问题和其他建议使用.ToList.ToArray,但我一个ObservableCollection,同时我显示屏幕上我也需要更新它们的元素。 我从来没遇到过这样的情况,希望有人帮我解决一下 的问题并解决,谢谢。

+2

这是其中一个“选择你的毒药”的情况 - 使用锁定或使用ToList/ToArray。 – dasblinkenlight

回答

0

也许这会帮助你。

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); 
      } 
     } 
    } 
} 
+0

嗯,我需要学习一下你的代码,从来没有使用过'IClonable',希望在你的一些解释中。谢谢。 – AgainMe

+0

我编辑代码。 – FreeMan

+0

你能告诉我如何使用它? – AgainMe