Несколько месяцев назад,делал один проект. Задача заключалась в том, чтобы отображать названия вызываемых билетов на большом дисплее. Вызывать могут одновременно несколько столов, и в любое время. А показывать билеты нужно последовательно. В итоге, получалась очередь билетов на отображение, которые показывались один за другим. Тогда, мне очень пригодилась реактивная очередь, но сейчас в Nuget репозиториях нет Contrib пакета Rx-Contrib для второй версии. О последнем решении я и хотел рассказать в этом посте.
Для примера, буду последовательно выводить кнопки нажатые на клавиатуре.
Сначала берем нужные пакеты из Nuget. Конечно — Rx-Main вместе с зависимостями: Rx-Core, Rx-Interfaces, Rx-Linq. Так как я делал WPF еще взял Rx-WPF — для работы с диспечером.
Готовим пользовательскую часть:
<window x:class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" title="MainWindow" height="350" width="525"> <window.resources> <storyboard x:key="animate"> <objectanimationusingkeyframes begintime="0:0:0" storyboard="" targetproperty="Visibility"> <discreteobjectkeyframe keytime="0"> <discreteobjectkeyframe.value> <visibility>Visible</visibility> </discreteobjectkeyframe.value> </discreteobjectkeyframe> </objectanimationusingkeyframes> <doubleanimation begintime="0:0:0.0" storyboard="" targetproperty="Opacity" from="0" to="1" duration="0:0:1"></doubleanimation> <doubleanimation begintime="0:0:2.0" storyboard="" targetproperty="Opacity" from="1" to="0" duration="0:0:1"></doubleanimation> <objectanimationusingkeyframes begintime="0:0:3" storyboard="" targetproperty="Visibility"> <discreteobjectkeyframe keytime="0"> <discreteobjectkeyframe.value> <visibility>Hidden</visibility> </discreteobjectkeyframe.value> </discreteobjectkeyframe> </objectanimationusingkeyframes> </storyboard> </window.resources> <grid> <canvas> <textblock canvas="" top="100" left="100" x:name="textbox" text="Trjam"> </textblock></canvas> </grid> </window>
Получаем текстовое поле с именем «textbox» и анимацию «animate». «animate» — будет полный цикл показа нашего символа, после окончания мы можем показать следующий символ.
Теперь сам код:
public partial class MainWindow : Window { protected Subject<string> keySubject = new Subject<string>(); AutoResetEvent revent = new AutoResetEvent(true); public MainWindow() { InitializeComponent(); InitSimpleQueue(); } protected override void OnKeyUp(KeyEventArgs e) { //заполняем наш субъект кнопками с клавиатуры keySubject.OnNext(e.Key.ToString()); } private void InitSimpleQueue() { //отпустить revent после завершения анимации ((Storyboard)FindResource("animate")).Completed += (s, e) => revent.Set(); keySubject .ObserveOn(Scheduler.TaskPool) .Select( s => { //ждать завершения НЕ в UI потоке revent.WaitOne(); return s; }) .ObserveOn(Dispatcher) .Subscribe( s => { //обновить поле и начать анимацию в контексте диспечера textbox.Text = s; ((Storyboard)FindResource("animate")).Begin(textbox); }); } }
Итог, я получил читабельный и последовательный код с помощью Rx, на подобное сейчас способен, разве что async. Можете представить, как бы этот код выглядел без Rx? В простейшем случае, это еще один поток с вечным циклом и ResetEvent-ом. Короче в 2 раза больше спегетти кода.
Метки:C#, Microsoft, OpenSource
Похожие статьи
- 12 февраля 2009 -- Мультипоточность в Windows.Forms и WPF (6)
- 22 августа 2008 -- Собственная страница для обработки ошибок на ASP.NET (0)
- 19 сентября 2010 -- StringTemplate на C# (Часть 2) (0)
- 8 марта 2011 -- C#: Silverlight таймаут (Timeout) (2)
- 31 августа 2009 -- CRUD на SQLite (5)