前言
我正在构建一个从互联网上抓取一些数据的应用程序。
需要实时更新数据,因此我运行无限循环
每次检查先前页面源是否更改。
所有这些数据都存储在ObservableCollection
内,如下所示:
private static ObservableCollection<Models.Event> _allMatches = new ObservableCollection<Models.Event>();
public ObservableCollection<Models.Event> AllMatches
{
get { return _matches; }
}
此O bservableCollection
绑定在ListView
中,如下所示:
<CollectionViewSource Source="{Binding AllMatches}" x:Key="GroupedItems">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="MatchNation" />
<PropertyGroupDescription PropertyName="MatchLeague" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
CollectionViewSource
帮助我使用ListView
组织GroupStyle
中的数据,在本例中为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,
...
};
}
}
此代码存在严重问题。我想有人已经知道会发生什么。
特别是我同时在方法AddAllListItem
中添加ObservableCollection中的项目
再次调用,我作为参数传递的匹配项已更改。这将产生
例外:
收藏已修改。枚举操作可能无法执行。
如何解决这种情况?
我已经阅读了几个问题,这里有问题和其他建议使用.ToList
或.ToArray
,但我有一个ObservableCollection,同时我在屏幕上显示元素我还需要更新他们。
我从来没有遇到过这样的情况,我希望有人帮助我解决这个问题
问题并解决它,谢谢。
答案 0 :(得分: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);
}
}
}
}