WP7 - Добавить в коллекцию через диспетчер - PullRequest
1 голос
/ 13 ноября 2011

Я загружаю некоторые XML-данные из твиттера в фоновом режиме, используя HttpWebRequest и Deployment.Current.Dispatcher.BeginInvoke() для обработки результатов, и устанавливаю их как ItemsSource моего ListBox. Теперь я хочу собрать XML из нескольких каналов Twitter, объединить их в коллекцию и назначить это свойству 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
                                            };
        });
    }
}

РЕДАКТИРОВАТЬ Кроме того, если это имеет значение, мне придется отсортировать окончательную коллекцию перед отправкой в ​​ItemsSource через TwitterItem.CreatedAt, поэтому, если кто-то может предложить оптимальную структуру данных для сортировки и легко ItemsSource задание, это было бы здорово!

Ответы [ 2 ]

2 голосов
/ 13 ноября 2011

Что вам нужно сделать, это создать постоянный, привязываемый объект коллекции где-то в вашем представлении и назначить его на 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 голос
/ 15 ноября 2011

Простым решением было бы использование 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) после того, как вы выясните, куда вставить новый элемент.Вероятно, есть несколько способов сделать это, но при условии, что вы анализируете свой create_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);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...