Параллельная наблюдаемая коллекция в Silverlight 5 - PullRequest
3 голосов
/ 08 марта 2012

Мне нужна поточно-ориентированная (одновременная) версия ObservableCollection в Silverlight 5. Я изо всех сил пытаюсь найти способ ее создания, учитывая отсутствие поддержки многопоточности в SL5 (нет ReaderWriterLock, нет Collections.Concurrent, чтобы говорить и т. д.).

Мне нужно, чтобы коллекция поддерживала привязку пользовательского интерфейса при обновлении другим потоком. Для меня неприемлемо отправлять все мои обновления в поток пользовательского интерфейса, когда процесс выполняется в фоновом режиме. В идеале, фоновый процесс может обновлять коллекцию по мере необходимости, а пользовательский интерфейс получает уведомления по мере возникновения изменений. Это возможно с .NET 4, и я нашел способы сделать это для WPF, но ничего для SL. Я не могу использовать примеры WPF, потому что они опираются на ReaderWriterLock, которого, AFAIK, нет в SL5.

Любое направление и / или примеры приветствуются.

UPDATE

В соответствии с асинхронным шаблоном связи, используемым (обязательным) в Silverlight, метод обратного вызова или обработчик выполняется в другом потоке. Используя TPL (как мы делаем), это продолжение задачи.

Поскольку этот код выполняется в другом потоке, любые операторы, которые влияют на ObservableCollection, должны быть перенаправлены обратно в поток пользовательского интерфейса. Это означает, что логика процесса и время теперь потребляют ресурсы потока пользовательского интерфейса.

Смысл одновременных коллекций в .NET состоит в том, чтобы позволить производителям и потребителям работать в разных потоках, в то же время беспрепятственно работая с общими данными в коллекции. «Производители» в клиентском приложении SL будут асинхронным обратным вызовом или продолжением задачи, а «потребители» - это пользовательский интерфейс, связанный с коллекцией.

1 Ответ

4 голосов
/ 22 марта 2012

Я также неоднократно сталкивался с этой проблемой, которая заставляла меня идти по той же дороге, на которую вы смотрите.Есть библиотека, которая мне очень помогла в этой задаче:

http://ch.codeplex.com/

Я реализовал свой собственный ConcurrentObservableCollection с использованием TinyReaderWriterLock и реализации IList, INotifyCollectionChanged, INotifyPropertyChanged

Я использовал этот пост в качестве отправной точки.http://www.deanchalk.me.uk/post/Thread-Safe-Dispatcher-Safe-Observable-Collection-for-WPF.aspx

В моей версии я разрешаю выполнять все вызовы в вызывающем потоке и только перенаправлять вызовы INotifyCollectionChanged и INotifyPropertyChanged обратно в поток пользовательского интерфейса следующим образом:

public void Add(T item)
{
    mSyncLock.LockForWriting();
    innerCollection.Add(item);
    mSyncLock.ReleaseForWriting();

    var index = IndexOf(item);

    OnNotifyPropertyChanged(COUNT_PROPERTY);
    OnNotifyPropertyChanged(INDEXER_PROPERTY);
    OnNotifyCollectionChanged(NotifyCollectionChangedAction.Add, item, index); // This is an overload of OnNotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
}

где

protected virtual void OnNotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
{
    if (CollectionChanged == null) return;

    ThreadSafeInvoke(() => CollectionChanged(this, e));
}

и

private static void ThreadSafeInvoke(Action action)
{
    if (Deployment.Current.Dispatcher.CheckAccess())
    {
        action.Invoke();
    }
    else
    {
        Deployment.Current.Dispatcher.BeginInvoke(action);
    }
}

Это хорошо сработало для меня.С блокировкой связано небольшое снижение производительности, но оно не имеет существенного значения для большинства применений.

...