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.
Brak komentarzy:
Prześlij komentarz