0

我正在构建一个 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 的其他两个函数,但是当我想将已处理的条目添加到ObservableCollectioningetTheResponse()方法时,会导致无效的跨线程访问错误。有什么想法吗?

代码:

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 
    { 
    }
}
4

3 回答 3

2

您需要使用DispatcherControl从非 UI 线程访问:

Deployment.Current.Dispatcher.BeginInvoke(()=>
{ 
     addToCollection(article.Element("title").Value,"CNN");   
});
于 2013-08-09T19:58:44.863 回答
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

于 2014-01-15T10:29:24.393 回答
0

您可以使用从ObservableCollection开始的Dispatcher以及 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
..
}
于 2014-01-22T07:32:11.827 回答