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

관련 문제