Картинка блога

Несколько месяцев назад,делал один проект. Задача заключалась в том, чтобы отображать названия вызываемых билетов на большом дисплее. Вызывать могут одновременно несколько столов, и в любое время. А показывать билеты нужно последовательно. В итоге, получалась очередь билетов на отображение, которые показывались один за другим. Тогда, мне очень пригодилась реактивная очередь, но сейчас в 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 раза больше спегетти кода.

Метки:, ,