2016-09-04 72 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