我正在后台通过Twitter Feed下载一些XML,使用HttpWebRequest
和Deployment.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
任务的数据结构,这太棒了!
答案 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);
}
}
}