F # - wydarzenia

Zdarzenia umożliwiają klasom wysyłanie i odbieranie wiadomości między sobą.

W graficznym interfejsie użytkownika zdarzenia to działania użytkownika, takie jak naciśnięcie klawisza, kliknięcia, ruchy myszą itp. Lub pewne zdarzenia, takie jak powiadomienia generowane przez system. Aplikacje muszą reagować na zdarzenia, gdy się pojawiają. Na przykład przerywa. Zdarzenia służą do komunikacji między procesami.

Obiekty komunikują się ze sobą poprzez synchroniczne przekazywanie wiadomości.

Wydarzenia są powiązane z innymi funkcjami; rejestr obiektówcallback funkcje do zdarzenia, a te wywołania zwrotne są wykonywane, gdy (i jeśli) zdarzenie jest wyzwalane przez jakiś obiekt.

Klasa zdarzenia i moduł zdarzeń

Klasa Control.Event <'T> pomaga w tworzeniu obserwowalnego obiektu lub zdarzenia.

Ma następujących członków instancji do pracy ze zdarzeniami:

Członek Opis
Publikować Publikuje obserwację jako wartość pierwszej klasy.
Cyngiel Uruchamia obserwację przy użyciu podanych parametrów.

Moduł Control.Event zapewnia funkcje do zarządzania strumieniami zdarzeń -

Wartość Opis
dodaj: ('T → jednostka) → Zdarzenie <' Del, 'T> → jednostka Uruchamia daną funkcję za każdym razem, gdy zostanie wyzwolone dane zdarzenie.
wybierz: (opcja 'T →' U) → IEvent <'Del,' T> → IEvent <'U> Zwraca nowe zdarzenie uruchamiane na wybranych wiadomościach z pierwotnego zdarzenia. Funkcja wyboru przenosi oryginalną wiadomość do opcjonalnej nowej wiadomości.
filter: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> Zwraca nowe zdarzenie, które nasłuchuje pierwotnego zdarzenia i wyzwala wynikowe zdarzenie tylko wtedy, gdy argument zdarzenia przekazuje daną funkcję.
mapa: ('T →' U) → IEvent <'Del,' T> → IEvent <'U> Zwraca nowe zdarzenie, które przekazuje wartości przekształcone przez daną funkcję.
scal: IEvent <'Del1,' T> → IEvent <'Del2,' T> → IEvent <'T> Uruchamia zdarzenie wyjściowe, gdy jedno ze zdarzeń wejściowych zostanie wyzwolone.
parami: IEvent <'Del,' T> → IEvent <'T *' T> Zwraca nowe zdarzenie, które jest wyzwalane przy drugim i kolejnym wyzwoleniu zdarzenia wejściowego. PlikNth wyzwolenie zdarzenia wejściowego powoduje przekazanie argumentów z N-1th i Nthwyzwalanie jako para. Argument przekazany doN-1th wyzwalanie jest utrzymywane w ukrytym stanie wewnętrznym do momentu Nth następuje wyzwalanie.
partycja: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> * IEvent <'T> Zwraca nowe zdarzenie, które nasłuchuje pierwotnego zdarzenia i wyzwala pierwsze zdarzenie wynikowe, jeśli zastosowanie predykatu do argumentów zdarzenia zwróciło wartość true, a drugie zdarzenie, jeśli zwróciło wartość false.
skanowanie: ('U →' T → 'U) →' U → IEvent <'Del,' T> → IEvent <'U> Zwraca nowe zdarzenie składające się z wyników zastosowania danej funkcji sumującej do kolejnych wartości wyzwalanych w zdarzeniu wejściowym. Pozycja stanu wewnętrznego rejestruje bieżącą wartość parametru stanu. Stan wewnętrzny nie jest blokowany podczas wykonywania funkcji akumulacji, dlatego należy uważać, aby wejście IEvent nie było wyzwalane przez wiele wątków jednocześnie.
split: ('T → Wybór <' U1, 'U2>) → IEvent <' Del, 'T> → IEvent <' U1> * IEvent <'U2> Zwraca nowe zdarzenie, które nasłuchuje pierwotnego zdarzenia i wyzwala pierwsze zdarzenie wynikowe, jeśli zastosowanie funkcji do argumentów zdarzenia zwróciło Choice1Of2, a drugie zdarzenie, jeśli zwróci Choice2Of2.

Tworzenie wydarzeń

Wydarzenia są tworzone i używane za pośrednictwem Eventklasa. Konstruktor Event służy do tworzenia zdarzenia.

Przykład

type Worker(name : string, shift : string) =
   let mutable _name = name;
   let mutable _shift = shift;
   let nameChanged = new Event<unit>() (* creates event *)
   let shiftChanged = new Event<unit>() (* creates event *)

   member this.Name
      with get() = _name
      and set(value) = _name <- value

   member this.Shift
      with get() = _shift
      and set(value) = _shift <- value

Następnie musisz ujawnić pole nameChanged jako publiczny element członkowski, aby nasłuchujący mogli podłączyć się do zdarzenia, dla którego użyjesz pola Publish własność imprezy -

type Worker(name : string, shift : string) =
   let mutable _name = name;
   let mutable _shift = shift;

   let nameChanged = new Event<unit>() (* creates event *)
   let shiftChanged = new Event<unit>() (* creates event *)

   member this.NameChanged = nameChanged.Publish (* exposed event handler *)
   member this.ShiftChanged = shiftChanged.Publish (* exposed event handler *)

   member this.Name
      with get() = _name
      and set(value) = _name <- value
      nameChanged.Trigger() (* invokes event handler *)

   member this.Shift
      with get() = _shift
      and set(value) = _shift <- value
   shiftChanged.Trigger() (* invokes event handler *)

Następnie dodajesz wywołania zwrotne do programów obsługi zdarzeń. Każdy program obsługi zdarzeń ma typ IEvent <'T>, który udostępnia kilka metod -

metoda Opis
val Dodaj: zdarzenie :( 'T → jednostka) → jednostka Łączy funkcję detektora ze zdarzeniem. Odbiornik zostanie wywołany po uruchomieniu zdarzenia.
val AddHandler: 'del → unit Łączy obiekt delegata programu obsługi ze zdarzeniem. Program obsługi można później usunąć za pomocą RemoveHandler. Odbiornik zostanie wywołany po uruchomieniu zdarzenia.
val RemoveHandler: 'del → unit Usuwa delegata nasłuchiwania z magazynu nasłuchiwania zdarzeń.

Poniższa sekcja zawiera pełny przykład.

Przykład

Poniższy przykład demonstruje koncepcję i techniki omówione powyżej -

type Worker(name : string, shift : string) =
   let mutable _name = name;
   let mutable _shift = shift;

   let nameChanged = new Event<unit>() (* creates event *)
   let shiftChanged = new Event<unit>() (* creates event *)

   member this.NameChanged = nameChanged.Publish (* exposed event handler *)
   member this.ShiftChanged = shiftChanged.Publish (* exposed event handler *)

   member this.Name
      with get() = _name
      and set(value) = 
         _name <- value
         nameChanged.Trigger() (* invokes event handler *)

   member this.Shift
      with get() = _shift
      and set(value) = 
         _shift <- value
         shiftChanged.Trigger() (* invokes event handler *)

let wk = new Worker("Wilson", "Evening")
wk.NameChanged.Add(fun () -> printfn "Worker changed name! New name: %s" wk.Name)
wk.Name <- "William"
wk.NameChanged.Add(fun () -> printfn "-- Another handler attached to NameChanged!")
wk.Name <- "Bill"

wk.ShiftChanged.Add(fun () -> printfn "Worker changed shift! New shift: %s" wk.Shift)
wk.Shift <- "Morning"
wk.ShiftChanged.Add(fun () -> printfn "-- Another handler attached to ShiftChanged!")
wk.Shift <- "Night"

Kiedy kompilujesz i wykonujesz program, daje to następujące dane wyjściowe -

Worker changed name! New name: William
Worker changed name! New name: Bill
-- Another handler attached to NameChanged!
Worker changed shift! New shift: Morning
Worker changed shift! New shift: Night
-- Another handler attached to ShiftChanged!