我在后台从twitter提要下载一些XML,使用HttpWebRequest和Deployment.Current.Dispatcher.BeginInvoke()来处理结果,并将它们设置为my ListBox的ItemsSource。我现在要做的是从多个twitter提要中收集XML,将它们组合成一个集合,并将其分配给ItemsSource属性。
我想我应该在类中使用一个计数器,在类中使用一个集合,并在每次请求完成时都进行更新,并且当计数器命中提要计数(7)时,相应地设置ItemsSource。问题是,我对C# / WP7非常陌生,这里有一些问题。这就是我现在所做的工作,这显然是错误的,因为无论最后哪个请求完成了对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
};
});
}
}编辑,如果有关系的话,在通过TwitterItem.CreatedAt将其发送到ItemsSource之前,我必须对最终的集合进行排序,所以如果有人能够为排序和简单的ItemsSource分配提出最佳的数据结构,那就太好了!
发布于 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的实现有点棘手,所以我在这里包括它:
<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))发布于 2011-11-15 18:05:56
一个简单的解决方案是使用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);
}
}
}https://stackoverflow.com/questions/8107665
复制相似问题