Помогите с RX простой Образец для этого - PullRequest
3 голосов
/ 14 октября 2010

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

  1. В приложении WPF у меня естьокно списка
  2. Процедура диспетчерского таймера добавляет несколько случайных чисел в локальный список каждые, скажем, 2 секунды
  3. Теперь я хочу настроить наблюдателя / наблюдателя для просмотра этого списка , поскольку он сохраняетсоздание и добавление самого последнего добавленного номера в коллекцию элементов списка.

Звучит очень просто, и я сделал третий бит в фоновом потоке (без RX, но со стандартнымпоиск в списке ) и легко добавляется в список.Когда я пытаюсь сделать то же самое без фонового работника и т. Д. И просто использую RX, я застреваю.

Извиняюсь за возможный глупый вопрос (для вас, экспертов по RX), но, пожалуйста, помогите как получить этот WPFсделано с использованием RX.

Спасибо.

Ответы [ 3 ]

9 голосов
/ 14 октября 2010

При работе с Rx необходимо учитывать двойственность между IEnumerable<T> & IObservable<T> (а также IEnumerator<T> & IObserver<T>).

Вы всегда должны искать объекты, которые реализуютIEnumerable<T> и подумайте, как бы вы заменили их на IObservable<T>.

. В своем вопросе вы говорите, что у вас есть таймер, добавляющий некоторые цифры к List<int>, который вы хотите наблюдать, и добавляете новые числасписок.Поэтому я хотел бы рассмотреть вопрос о замене списка на IObservable<int>.Хитрость здесь не в том, чтобы посмотреть список (или ObservableCollection<int>), а в том, чтобы использовать Rx в качестве основной части вашего кода.

Итак, вот простой пример.

Начните с основных элементов, описанных в вашем вопросе:

var dispatchTimer = new DispatcherTimer();
var random = new Random();
var listBox = new ListBox();

Создайте наблюдаемую из dispatchTimer:

IObservable<IEvent<EventArgs>> ticks =
    Observable.FromEvent(
        h => dispatchTimer.Tick += h,
        h => dispatchTimer.Tick -= h);

Запросите наблюдаемую для создания новой наблюдаемой случайных чисел:

IObservable<int> randomNumbers =
    from tick in ticks
    select random.Next(1, 11);

Теперь подпишитесь на случайные числа, наблюдаемые для обновления поля списка:

_updateListBoxSubscription =
    randomNumbers.ObserveOnDispatcher().Subscribe(n => listBox.Items.Add(n));

Вызов .ObserveOnDispatcher() обеспечит добавление номеров в поле списка наПоток пользовательского интерфейса.

Вам необходимо определить поле или свойство для хранения ссылки на подписку, чтобы она не собирала мусор.Это именно то, что поля обработчика событий делают, когда вы добавляете обработчик, но с Rx вы должны явно сделать это.

private IDisposable _updateListBoxSubscription;

Итак, у вас теперь есть список, обновляемый из случайных чисел, сгенерированных винтервал, указанный во времени.

Это так просто.Надеюсь, это поможет.

4 голосов
/ 06 января 2011

Эй, ребята, все это выглядит великолепно, но вы фактически убили свою тестируемость кода.Вам будет сложно быстро выполнить модульное тестирование этого кода, так как вам нужно будет запустить кадр диспетчера (чёрт!).

Позволяет перевернуть голову, не использовать DispatcherTimer, а использовать метод планирования и интервала Rx..

Итак, код:

var random = new Random();
var ticks = Observable.Interval(TimeSpan.FromSeconds(1), Scheduler.Dispatcher);
var randomNumbers = from tick in ticks
                    select random.Next(1, 11);
_updateListBoxSubscription = randomNumbers
    .Subscribe(n => listBox.Items.Add(n));

Однако это сложно проверить, поскольку у вас есть прямая ссылка на DispatcherScheduler, который в свою очередь ссылается на Dispatcher.

Что вынужно сделать это, чтобы внедрить планировщик (IScheduler), чтобы его можно было проверять при тестировании.

var random = new Random();
var ticks = Observable.Interval(TimeSpan.FromSeconds(1), _schedulerProvider.Dispatcher);
var randomNumbers = from tick in ticks
                    select random.Next(1, 11);
_updateListBoxSubscription = randomNumbers
    .Subscribe(n => listBox.Items.Add(n));

, а затем в тестах вы возвращаете TestScheduler вместо DispatcherScheduler.

Проверьте мойсообщения в блоге по расписанию и по тестированию в серии Rx вводный для полного описания.
ОБНОВЛЕНИЕ : улучшенное содержаниедля изучения планирования с помощью Rx можно найти в моей книге IntroToRx.com , в частности главу о Планирование и создание потоков

1 голос
/ 14 октября 2010

Мне не совсем понятно, что вы делаете, но, похоже, проблема здесь List<int> - он не "изначально" поддерживает Rx, потому что у него нет никаких средств уведомления наблюдателей.при добавлении нового элемента.

Когда вы подписываетесь на List<int>, он сразу же просто выдает текущее содержимое подписчику - он не будет зависать и прислушиваться к дополнительным изменениям.1006 * Могу ли я предположить, что ObservableCollection<T>, вероятно, более подходит для вас?

...