środa, 15 lutego 2012

[RX 12] Reactive Extensions, przykład kompozycji zdarzeń [PL]

Niniejszy post jest kontynuacją cyklu o Reactive Extensions dla .NET ([RX 1], [RX 2], [RX 3], [RX 4], [RX 5], [RX 6], [RX 7], [RX 8], [RX9], [RX10], [RX11]) stanowi on kontynuację przykładu z poprzedniego wpisu i skupia się na kompozycji zdarzeń.
Przejdźmy może do ciekawszego przykładu, w którym będziemy rysować linie. Linia będzie rysowana poprzez wskazanie przyciśnięciem lewego klawisza myszki jej początku, przesunięcie myszki i wskazanie końca linii poprzez zwolnienie lewego przycisku. Wymaga to złożenie dwóch zdarzeń: MouseDown i MouseUp, odczytu pozycji myszki dla każdego z nich i narysowaniu linii za każdym razem, gdy obydwa zdarzenia miały miejsce:
private void Window_Initialized( object sender, EventArgs e )
{
  var mouseDown = from ev in Observable.FromEventPattern<MouseButtonEventHandler, MouseEventArgs>( h => this.MouseDown += h, h => this.MouseDown -= h )
                    select ev.EventArgs.GetPosition( this );
  var mouseUp = from ev in Observable.FromEventPattern<MouseButtonEventHandler, MouseEventArgs>( h => this.MouseUp += h, h => this.MouseUp -= h )
                    select ev.EventArgs.GetPosition( this );

  var drawline = mouseDown.Zip( mouseUp,
    ( down, up ) =>
    {
      return new Point[] { down, up };
    } );

  drawline.ObserveOn( DispatcherScheduler.Instance ).Subscribe( line =>
  {
    var myLine = new Line();
    myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
    myLine.X1 = line[0].X;
    myLine.X2 = line[1].X;
    myLine.Y1 = line[0].Y;
    myLine.Y2 = line[1].Y;
    grid.Children.Add( myLine );
  } );
}
Jak widać, najpierw miało miejsce stworzenie obserwowalnych i przefiltrowanych (potrzebne były tylko pozycje myszy) kolekcji na podstawie dwóch interesujących zdarzeń. Następnie dokonano kompozycji tych dwóch kolekcji (tutaj funkcją Zip), tak że uzyskano pary punktów po każdorazowym zajściu obydwu zdarzeń. Dodatkowo ustawiono, że obserwacja będzie się odbywała na wątku dyspozytora aplikacji WPF, co pozwoli na bezproblemową modyfikację kontrolek. W ostatnim kroku skonfigurowano subskrypcję, tak aby po pojawieniu się każdej pary zdarzeń nastąpiło dodawanie linii do istniejącej kontrolki. Zagadnienie rysowania linii, udało się rozwiązać w kilkunastu liniach kodu.
Warto tutaj zwrócić jeszcze uwagę na dwie sprawy. Pierwszą z nich jest kompozycja zdarzeń, wykorzystana funkcja Zip nie jest jedyną możliwością, warto również zapoznać się z innymi, np. Amb, Concat, SelectMany, Merge, CombineLatest, ForkJoin. Drugą jest wsparcie dla tworzenia oprogramowania wielowątkowego, czyli różnego rodzaju planiści (np. CurrentThreadScheduler, ImmediateScheduler, NewThreadScheduler,TaskPoolScheduler, ThreadPoolScheduler, DispatcherScheduler, ControlScheduler), pozwalający na wykonywanie obserwacji na różnych wątkach, w tym wątkach związanych z graficznym interfejsem użytkownika.
Promuj

Brak komentarzy:

Prześlij komentarz

Posty powiązane / Related posts