我正在构建一个RSS提要阅读器。我使用Visual studio创建了一个启动应用程序。在它的主页面上我添加了一个指向新数据透视页面的链接。所有rss事情都发生在我的数据透视页面中。现在我的RSS订阅源列表框,我最初使用以下代码设置了一些列表项:
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是从服务器获取并解析的,但是当我想在ObservableCollection
方法中将处理过的条目添加到getTheResponse()
时,会导致无效的跨线程访问error.Any ideas?
代码:
private void getMeTheNews()
{
String url = "http://rss.cnn.com/rss/edition.rss";
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.BeginGetResponse(getTheResponse, webRequest);
}
private void getTheResponse(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
if (request != null)
{
try
{
WebResponse response = request.EndGetResponse(result);
XDocument doc = XDocument.Load(response.GetResponseStream());
IEnumerable<XElement> articles = doc.Descendants("item");
foreach (var article in articles) {
System.Diagnostics.Debug.WriteLine(article);
try
{
System.Diagnostics.Debug.WriteLine(article.Element("title").Value);
addToCollection(article.Element("title").Value,"CNN");
}
catch (NullReferenceException e) {
System.Diagnostics.Debug.WriteLine(e.StackTrace);
}
}
}
catch(WebException e) {
System.Diagnostics.Debug.WriteLine(e.StackTrace.ToString());
}
}
else
{
}
}
答案 0 :(得分:2)
您需要使用Dispatcher
从非UI线程访问Control
:
Deployment.Current.Dispatcher.BeginInvoke(()=>
{
addToCollection(article.Element("title").Value,"CNN");
});
答案 1 :(得分:0)
跨线程集合同步
将ListBox绑定放到 ObservableCollection ,当数据发生更改时,更新ListBox,因为实现了INotifyCollectionChanged。 缺陷dell'ObservableCollection是数据只能由创建它的线程更改。
SynchronizedCollection 没有多线程的问题,但是没有更新ListBox,因为它没有实现INotifyCollectionChanged,即使你实现了INotifyCollectionChanged,也只能调用CollectionChanged(this,e)从创建它的线程..所以它不起作用。
<强>结论强>
- 如果您想要一个自动更新的单线程列表,请使用 ObservableCollection
- 如果您想要一个未自动更新但多线程的列表,请使用 SynchronizedCollection
- 如果您想要两者,请以这种方式使用Framework 4.5 ,BindingOperations.EnableCollectionSynchronization和ObservableCollection():
/ / Creates the lock object somewhere
private static object _lock = new object () ;
...
/ / Enable the cross acces to this collection elsewhere
BindingOperations.EnableCollectionSynchronization ( _persons , _lock )
完整示例 http://10rem.net/blog/2012/01/20/wpf-45-cross-thread-collection-synchronization-redux
答案 2 :(得分:0)
你可以使用 Disservcher 从 ObservableCollection 开始,使用方法OnCollectionChanged的ovverride
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
..
}