Как стать автором
Обновить

LINQ to Events — декларативная работа с асинхронным интерфейсом

Время на прочтение3 мин
Количество просмотров1.3K
Наткнулся на очень интересное расширение для LINQ позволяющее декларативно работать с асинхронным интерфейсом ( themechanicalbride.blogspot.com/2009/07/introducing-rx-linq-to-events.html ). Сейчас расширение существует как часть Silverlight Toolkit (Rx framework), но в последствии станет частью .NET 4.0 (System.Reactive.dll).

Идея в том, чтобы стереть границы между IEnumerable и IObservable интерфейсами (читай между Iterator и Observer паттернами). Асинхронные события представляются как последовательность данных, возвращаемых будто бы по yield return. А это в свою очередь позволяет работать с данной последовательностью через LINQ в функциональном, декларативном стиле.

Например, можно использовать LINQ для формулирования выражений о перетаскивании контролов:

IObservable<Event<MouseEventArgs>> draggingEvent =
    from mouseLeftDownEvent in control.GetMouseLeftDown()
    from mouseMoveEvent in control.GetMouseMove().Until(control.GetMouseLeftUp())
    select mouseMoveEvent;


Выражение гласит следующее: для каждого нажатия на левую кнопку мыши получить каждое событие перемещения мыши до тех пор, пока левая кнопка мыши не будет отжата.

Таким образом from позволяет декларативно описывать последовательность событий. В противном случае, потребовалось бы создавать конечный автомат и устанавливать флаг нажатия на левую кнопку мыши. А в обработчике перемещения мыши тестировать этот флаг и изменять поведение обработчика в зависимости от него. Использование же Rx фреймворка позволяет описать последовательность событий декларативно и не вводить дополнительные переменные.

Подобным образом можно тестировать GUI где переходы из состояния в состояние не мгновенны, а происходят с анимацией, окончания которой необходимо дождаться прежде чем производить обращения к свойствам контрола.

Rating rating = new Rating();
IObservable<Unit> test =
   ObservableExtensions
      .DoAsync(() => TestPanel.Children.Add(rating)) // добавить контрол на панель
      .WaitFor(TestPanel.GetLayoutUpdated()) // подождать пока появится
      .DoAsync(() => rating.Value = 1.0) // установить свойство
      .WaitFor(
         rating
            .GetActualValueChanged() // ждать пока не установится
            .SkipWhile(actualValueChangedEvent => // новое значение свойства
               actualValueChangedEvent.EventArgs.NewValue != rating.Value))
      .Assert(() => rating.GetRatingItems().Last().ActualValue == 1.0); // Assert

// очистка ресурсов по завершению теста
test.Subscribe(() => TestPanel.Children.Remove(rating));


Автор оригинального поста обещает в ближайшее время осветить межпоточное взаимодействие с использованием этого фреймворка.

Области применения


  • Построение КА для визуального интерфейса пользователя.
  • Координирование событий Workflow.
  • Координирование сообщений с периферийными устройствами. В том числе с сетью (веб-службами) и с любым асинхронным IO.
  • Работа с цепочками событий.

Адаптация под WPF


silverlight.codeplex.com/SourceControl/ListDownloadableCommits.aspx
evain.net/blog/articles/2009/07/30/rebasing-system-reactive-to-the-net-clr

Похоже, ветки кода, адаптированной под WPF, пока нет, но обещают добавить в .NET 4.0. Однако уже сейчас можно взять сырцы и поковырять вручную.

Bindable LINQ


Развитие идеи — осуществление биндинга к декларативно описанным цепочкам событий. При изменении зависимого свойства, GUI перерисовывается чтобы отразить изменения. В Rx этого сейчас нет. Однако подобная связь с INotifyPropertyChanged есть в следующих проектах (сами проекты пока не смотрел):
Теги:
Хабы:
+17
Комментарии6

Публикации

Изменить настройки темы

Истории

Работа

.NET разработчик
68 вакансий

Ближайшие события

PG Bootcamp 2024
Дата16 апреля
Время09:30 – 21:00
Место
МинскОнлайн
EvaConf 2024
Дата16 апреля
Время11:00 – 16:00
Место
МоскваОнлайн
Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн