首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WP7 -跨调度器向集合添加

WP7 -跨调度器向集合添加
EN

Stack Overflow用户
提问于 2011-11-12 21:24:12
回答 2查看 588关注 0票数 1

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

我想我应该在类中使用一个计数器,在类中使用一个集合,并在每次请求完成时都进行更新,并且当计数器命中提要计数(7)时,相应地设置ItemsSource。问题是,我对C# / WP7非常陌生,这里有一些问题。这就是我现在所做的工作,这显然是错误的,因为无论最后哪个请求完成了对ItemsSoure的覆盖,而且,我不知道如何将它们放入一个“全局”容器中,因为Dispatcher似乎有一个不同的范围:

代码语言:javascript
复制
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
                                            };
        });
    }
}

编辑,如果有关系的话,在通过TwitterItem.CreatedAt将其发送到ItemsSource之前,我必须对最终的集合进行排序,所以如果有人能够为排序和简单的ItemsSource分配提出最佳的数据结构,那就太好了!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-11-13 00:21:25

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

您希望在修改集合时选择支持通知的现有集合类型,或者自己实现通知类型。在Silverlight,我认为你最好的(只有?)打赌是System.Collections.ObjectModel.ObservableCollection。另一个选项是在从不同类型的集合继承的自定义类中实现System.Collections.Specialized.INotifyCollectionChanged

至于排序,如果到达的数据总是比现有的数据晚,那么您可以在将新项添加到集合之前对它们进行排序(如果要在集合顶部显示最新的项,则可能希望将它们插入集合的前面)。

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

基于System.Collection.Generic.List创建一个新的集合类(这包含一个本机排序()方法)。

在这个类中实现INotifyCollectionChanged,并在添加和排序记录之后使用NotifyCollectionChangedAction.Reset操作引发它的CollectionChanged事件。

在item类上实现IComparable,以便根据规则对项进行排序。

实现INotifyCollectionChanged的更新

大多数建议都很简单,但是INotifyCollectionChanged的实现有点棘手,所以我在这里包括它:

代码语言:javascript
复制
<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

若要引发此事件,使消费者知道列表中的更改:

代码语言:javascript
复制
Call RaiseListChangedEvent(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
票数 2
EN

Stack Overflow用户

发布于 2011-11-15 18:05:56

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

代码语言:javascript
复制
TwitterListBox.ItemsSource = new ObservableCollection<TwitterItem>().

每当您收到更多要添加的项目时,只需做:

代码语言:javascript
复制
var itemsSource = (ObservableCollection<TwitterItem>)TwitterListBox.ItemsSource;

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

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

代码语言:javascript
复制
CreatedAt = DateTime.ParseExact(createdAt, "ddd MMM dd HH:mm:ss zzz yyyy", CultureInfo.InvariantCulture)

你大概是这样做的:

代码语言:javascript
复制
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++;
}

或者一个更好的解决方案:

代码语言:javascript
复制
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);
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8107665

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档