C# 更新列表框结果为;无效的跨线程访问。”;
我正在构建rss提要阅读器。我使用Visual studio创建了一个入门应用程序。在它的主页上,我添加了一个指向新pivot页面的链接。所有rss事件都发生在我的pivot页面中。现在,在我的rss提要列表框中,我最初使用以下代码设置了一些列表项:C# 更新列表框结果为;无效的跨线程访问。”;,c#,windows,windows-phone-7,windows-phone-8,C#,Windows,Windows Phone 7,Windows Phone 8,我正在构建rss提要阅读器。我使用Visual studio创建了一个入门应用程序。在它的主页上,我添加了一个指向新pivot页面的链接。所有rss事件都发生在我的pivot页面中。现在,在我的rss提要列表框中,我最初使用以下代码设置了一些列表项: public PivotPage1() { InitializeComponent(); getMeTheNews(); addToCollection("Android is going up","TechCrunch")
public PivotPage1()
{
InitializeComponent();
getMeTheNews();
addToCollection("Android is going up","TechCrunch");
lstBox.DataContext = theCollection;
}
private void addToCollection(string p1, string p2)
{
theCollection.Add(new NewsArticle(p1,p2));
}
下面是另外两个函数,rss是从服务器获取并解析的,但是当我想在getTheResponse()
方法中将处理过的条目添加到observeCollection
中时,它会导致无效的跨线程访问错误。有什么想法吗
代码:
private void getMethNews()
{
字符串url=”http://rss.cnn.com/rss/edition.rss";
HttpWebRequestWebRequest=(HttpWebRequest)HttpWebRequest.Create(url);
BeginGetResponse(getTheResponse,webRequest);
}
private void getTheResponse(IAsyncResult结果)
{
HttpWebRequest request=result.AsyncState作为HttpWebRequest;
if(请求!=null)
{
尝试
{
WebResponse=request.EndGetResponse(结果);
XDocument doc=XDocument.Load(response.GetResponseStream());
IEnumerable articles=文件子体(“项目”);
foreach(条款中的var条款){
系统.诊断.调试.编写(文章);
尝试
{
System.Diagnostics.Debug.WriteLine(article.Element(“title”).Value);
addToCollection(article.Element(“title”).Value,“CNN”);
}
捕获(NullReferenceException e){
系统.诊断.调试.写线(如StackTrace);
}
}
}
捕获(WebE例外){
System.Diagnostics.Debug.WriteLine(例如StackTrace.ToString());
}
}
其他的
{
}
}
您需要使用调度程序
从非UI线程访问控件
:
Deployment.Current.Dispatcher.BeginInvoke(()=>
{
addToCollection(article.Element("title").Value,"CNN");
});
跨线程收集同步 将列表框绑定到一个可观察集合,当数据更改时,您会更新列表框,因为INotifyCollectionChanged已实现。 dell的ObservableCollection的缺陷在于,数据只能由创建它的线程更改 SynchronizedCollection不存在多线程问题,但不会更新列表框,因为它未在INotifyCollectionChanged中实现,即使实现INotifyCollectionChanged,也只能从创建它的线程调用CollectionChanged(this,e)。。所以它不起作用 结论 -如果希望列表是自动更新的单线程请使用可观察收集 -如果希望列表不是自动更新的,而是多线程的,请使用同步收集 -如果两者都需要,请以以下方式使用Framework 4.5、BindingOperations.EnableCollectionsSynchronization和ObservableCollection():
/ / Creates the lock object somewhere
private static object _lock = new object () ;
...
/ / Enable the cross acces to this collection elsewhere
BindingOperations.EnableCollectionSynchronization ( _persons , _lock )
完整样本
您可以使用调度程序从ObservableCollection开始,同时更改收集方法的覆盖范围
public class MyObservableCollectionOverrideCollChangOfObjects<T> : ObservableCollection<T>
{
...
#region CollectionChanged
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);
}
}
}
#endregion
..
}
公共类MyObservableCollectionOverrideCollChangof对象:ObservableCollection
{
...
#区域集合已更改
公共覆盖事件NotifyCollectionChangedEventHandler CollectionChanged;
CollectionChanged上的受保护覆盖无效(NotifyCollectionChangedEventArgs e)
{
var eh=集合更改;
如果(eh!=null)
{
Dispatcher Dispatcher=(来自eh.GetInvocationList()中的NotifyCollectionChangedEventHandler nh)
让dpo=nh.Target作为DispatcherObject
其中dpo!=null
选择dpo.Dispatcher).FirstOrDefault();
if(dispatcher!=null&&dispatcher.CheckAccess()=false)
{
调用(DispatcherPriority.DataBind,(Action)(()=>OnCollectionChanged(e));
}
其他的
{
foreach(eh.GetInvocationList()中的NotifyCollectionChangedEventHandler nh)
调用(本,e);
}
}
}
#端区
..
}
public class MyObservableCollectionOverrideCollChangOfObjects<T> : ObservableCollection<T>
{
...
#region CollectionChanged
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);
}
}
}
#endregion
..
}