WP7 - 跨调度程序添加到集合

时间:2011-11-12 21:24:12

标签: c# windows-phone-7 asynchronous httpwebrequest

我正在后台通过Twitter Feed下载一些XML,使用HttpWebRequestDeployment.Current.Dispatcher.BeginInvoke()来处理结果,并将其设置为我ItemsSource的{​​{1}} }。我现在要做的是从多个twitter提要中收集XML,将它们组合成一个集合,并将其分配给ListBox属性。

我想我会在课堂上使用一个计数器,并在课堂上使用一个集合,每次请求完成时都会更新,当计数器达到Feed计数(7)时,设置ItemsSource因此。问题是,我对C#/ WP7很新,我在这里遇到了一些问题。这就是我现在所做的,这显然是错误的,因为无论哪个请求最后都会覆盖ItemsSource,而且,我不知道如何将它们粘贴到'全局'容器中,因为它看起来像{ {1}}的范围不同:

ItemsSoure

编辑此外,如果重要,我必须先对最终收藏品进行排序,然后再通过Dispatcher将其发送到string[] feeds = { "badreligion", "DoctorGraffin", "BrettGurewitz", "jay_bentley", "brtour", "GregHetson", "theBRpage" }; // invoked in the constructor private void StartTwitterUpdate() { foreach (string feed in feeds) { HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=" + feed)); request.BeginGetResponse(new AsyncCallback(twitter_DownloadStringCompleted), request); } } // the AsyncCallback void twitter_DownloadStringCompleted(IAsyncResult asynchronousResult) { HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState; HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult); using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream())) { string resultString = streamReader1.ReadToEnd(); XElement xmlTweets = XElement.Parse(resultString); // here I need to add to a collection, and if the max is hit, set the ItemsSource Deployment.Current.Dispatcher.BeginInvoke(() => { TwitterListBox.ItemsSource = from tweet in xmlTweets.Descendants("status") select new TwitterItem { CreatedAt = tweet.Element("created_at").Value, Id = tweet.Element("id").Value, ImageSource = tweet.Element("user").Element("profile_image_url").Value, Message = tweet.Element("text").Value, UserName = "@" + tweet.Element("user").Element("screen_name").Value }; }); } } ,以便有人建议最佳用于排序和轻松ItemsSource任务的数据结构,这太棒了!

2 个答案:

答案 0 :(得分:2)

您需要做的是在视图中的某个位置创建一个持久的,可绑定的集合对象,并将其分配给ItemsSource一次。收到新项目后,只需将它们添加到集合中即可。

您需要选择在修改集合时支持通知的现有集合类型,或者自己实现。在Silverlight中,我认为你最好(仅限?)的赌注是System.Collections.ObjectModel.ObservableCollection。另一种选择是在自定义类中实现System.Collections.Specialized.INotifyCollectionChanged,该类继承自不同类型的Collection。

至于排序,如果您到达的数据总是晚于现有数据,那么您可以在将新项目添加到集合之前对其进行排序(如果您愿意,可以将它们插入集合的前面)想要用最新的显示它们。)

但是,如果每次添加新记录时都需要对整个集合进行排序,那么您需要在项目类上实施System.IComparable。在这种情况下,我建议采用以下方法:

基于System.Collection.Generic.List创建一个新的集合类(这包含一个原生的Sort()方法)。

在此类中实施INotifyCollectionChanged,并在添加和排序记录后使用CollectionChanged操作引发其NotifyCollectionChangedAction.Reset事件。

在您的商品类上实施IComparable,以便根据您的规则对商品进行分类。

通过实施INotifyCollectionChanged进行更新

大多数建议非常简单,但是INotifyCollectionChanged的实现有点棘手,所以我把它包含在这里:

<NonSerialized()> _
Private m_ListChangedEvent As NotifyCollectionChangedEventHandler

''' <summary>
''' This event is raised whenever the list is changed and implements the IBindingList ListChanged event
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Public Custom Event ListChanged As NotifyCollectionChangedEventHandler Implements INotifyCollectionChanged.CollectionChanged
    <MethodImpl(MethodImplOptions.Synchronized)> _
    AddHandler(ByVal value As NotifyCollectionChangedEventHandler)
        m_ListChangedEvent = DirectCast([Delegate].Combine(m_ListChangedEvent, value), NotifyCollectionChangedEventHandler)
    End AddHandler

    <MethodImpl(MethodImplOptions.Synchronized)> _
    RemoveHandler(ByVal value As NotifyCollectionChangedEventHandler)
        m_ListChangedEvent = DirectCast([Delegate].Remove(m_ListChangedEvent, value), NotifyCollectionChangedEventHandler)
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs)
        If m_ListChangedEvent IsNot Nothing Then
            m_ListChangedEvent.Invoke(sender, e)
        End If
    End RaiseEvent
End Event

要举起此活动,以便消费者了解列表的更改:

Call RaiseListChangedEvent(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))

答案 1 :(得分:1)

一个简单的解决方案是使用ObservableCollection作为ItemsSource:

TwitterListBox.ItemsSource = new ObservableCollection<TwitterItem>().

每当您收到更多要添加的项目时 - 只需执行以下操作:

var itemsSource = (ObservableCollection<TwitterItem>)TwitterListBox.ItemsSource;

foreach(var twitterItem in newTweets)
{
    itemsSource.Add(twitterItem);
}

如果你想要这些排序 - 你需要在找出插入新项目的位置后执行itemsSource.Insert(twitterItem,i)。可能有几种方法可以做到这一点,但假设你像这样解析你的created_at:

CreatedAt = DateTime.ParseExact(createdAt, "ddd MMM dd HH:mm:ss zzz yyyy", CultureInfo.InvariantCulture)

这大致是你能做到的:

int i = 0; // insert index
int j = 0; // new items index

while (j < newTweets.Count)
{
    while (i < itemsSource.Count &&
        itemsSource[i].CreatedAt >= newTweets[j].CreatedAt)
    {
        i++;
    }

    itemsSource.Insert(i, newTweets[j]);
    j++;
}

或者更高级的解决方案:

public partial class MainPage : PhoneApplicationPage
{
    // Constructor
    public MainPage()
    {
        InitializeComponent();

        var itemsSource = new ObservableCollection<TwitterItem>();
        var initialTweets = new[]
                                {
                                    new TwitterItem
                                        {CreatedAt = DateTime.Now.AddMinutes(-3)},
                                    new TwitterItem
                                        {CreatedAt = DateTime.Now.AddMinutes(-2)},
                                    new TwitterItem
                                        {CreatedAt = DateTime.Now.AddMinutes(-1)}
                                };
        itemsSource.Merge(initialTweets.OrderByDescending(ti => ti.CreatedAt));

        var newTweets = new List<TwitterItem>();
        newTweets.Add(new TwitterItem {CreatedAt = DateTime.Now.AddMinutes(-3.5)});
        newTweets.Add(new TwitterItem {CreatedAt = DateTime.Now.AddMinutes(-2.5)});
        newTweets.Add(new TwitterItem {CreatedAt = DateTime.Now.AddMinutes(-1.5)});
        newTweets.Add(new TwitterItem {CreatedAt = DateTime.Now.AddMinutes(-0.5)});
        itemsSource.Merge(newTweets.OrderByDescending(ti => ti.CreatedAt));

        foreach (var twitterItem in itemsSource)
        {
            Debug.WriteLine(twitterItem.CreatedAt.ToString());
        }
    }
}

public class TwitterItem
{
    public DateTime CreatedAt;
}

public static class ObservableTwitterItemsExtensions
{
    public static void Merge(
        this ObservableCollection<TwitterItem> target, IEnumerable<TwitterItem> source)
    {
        int i = 0; // insert index

        foreach (var newTwitterItem in source)
        {
            while (i < target.Count &&
                target[i].CreatedAt >= newTwitterItem.CreatedAt)
            {
                i++;
            }

            target.Insert(i, newTwitterItem);
        }
    }
}