F # - Événements

Les événements permettent aux classes d'envoyer et de recevoir des messages entre elles.

Dans l'interface graphique, les événements sont des actions de l'utilisateur telles que la pression de touches, les clics, les mouvements de la souris, etc., ou certaines occurrences telles que les notifications générées par le système. Les applications doivent répondre aux événements lorsqu'ils se produisent. Par exemple, les interruptions. Les événements sont utilisés pour la communication inter-processus.

Les objets communiquent entre eux grâce à la transmission synchrone des messages.

Les événements sont associés à d'autres fonctions; registre d'objetscallback fonctions à un événement, et ces rappels sont exécutés lorsque (et si) l'événement est déclenché par un objet.

La classe d'événements et le module d'événements

La classe Control.Event <'T> aide à créer un objet ou un événement observable.

Il a les membres d'instance suivants pour travailler avec les événements -

Membre La description
Publier Publie une observation en tant que valeur de première classe.
Déclencheur Déclenche une observation en utilisant les paramètres donnés.

Le module Control.Event fournit des fonctions de gestion des flux d'événements -

Valeur La description
ajouter: ('T → unité) → Evénement <' Del, 'T> → unité Exécute la fonction donnée à chaque fois que l'événement donné est déclenché.
choisissez: (option 'T →' U) → IEvent <'Del,' T> → IEvent <'U> Renvoie un nouvel événement qui se déclenche sur une sélection de messages de l'événement d'origine. La fonction de sélection prend un message d'origine dans un nouveau message facultatif.
filtre: ('T → booléen) → IEvent <' Del, 'T> → IEvent <' T> Renvoie un nouvel événement qui écoute l'événement d'origine et déclenche l'événement résultant uniquement lorsque l'argument de l'événement passe la fonction donnée.
map: ('T →' U) → IEvent <'Del,' T> → IEvent <'U> Renvoie un nouvel événement qui transmet les valeurs transformées par la fonction donnée.
fusion: IEvent <'Del1,' T> → IEvent <'Del2,' T> → IEvent <'T> Déclenche l'événement de sortie lorsque l'un des événements d'entrée se déclenche.
par paire: IEvent <'Del,' T> → IEvent <'T *' T> Renvoie un nouvel événement qui se déclenche au deuxième déclenchement et au déclenchement suivant de l'événement d'entrée. leNth le déclenchement de l'événement d'entrée transmet les arguments du N-1th et Nthse déclenchant en paire. L'argument passé auN-1th le déclenchement est maintenu dans l'état interne caché jusqu'à ce que le Nth le déclenchement se produit.
partition: ('T → booléen) → IEvent <' Del, 'T> → IEvent <' T> * IEvent <'T> Renvoie un nouvel événement qui écoute l'événement d'origine et déclenche le premier événement résultant si l'application du prédicat aux arguments d'événement a renvoyé true, et le deuxième événement s'il a renvoyé false.
scan: ('U →' T → 'U) →' U → IEvent <'Del,' T> → IEvent <'U> Renvoie un nouvel événement constitué des résultats de l'application de la fonction d'accumulation donnée à des valeurs successives déclenchées sur l'événement d'entrée. Un élément d'état interne enregistre la valeur actuelle du paramètre d'état. L'état interne n'est pas verrouillé pendant l'exécution de la fonction d'accumulation, il faut donc veiller à ce que l'entrée IEvent ne soit pas déclenchée par plusieurs threads simultanément.
split: ('T → Choice <' U1, 'U2>) → IEvent <' Del, 'T> → IEvent <' U1> * IEvent <'U2> Renvoie un nouvel événement qui écoute l'événement d'origine et déclenche le premier événement résultant si l'application de la fonction aux arguments d'événement a renvoyé un Choice1Of2, et le deuxième événement s'il renvoie un Choice2Of2.

Créer des événements

Les événements sont créés et utilisés via le Eventclasse. Le constructeur Event est utilisé pour créer un événement.

Exemple

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

Après cela, vous devez exposer le champ nameChanged en tant que membre public, afin que les écouteurs puissent se connecter à l'événement pour lequel vous utilisez le Publish propriété de l'événement -

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 *)

Ensuite, vous ajoutez des rappels aux gestionnaires d'événements. Chaque gestionnaire d'événements a le type IEvent <'T>, qui fournit plusieurs méthodes -

Méthode La description
val Ajouter: événement :( 'T → unité) → unité Connecte une fonction d'écoute à l'événement. L'écouteur sera appelé lorsque l'événement est déclenché.
val AddHandler: 'del → unité Connecte un objet délégué de gestionnaire à l'événement. Un gestionnaire peut être supprimé ultérieurement à l'aide de RemoveHandler. L'écouteur sera appelé lorsque l'événement est déclenché.
val RemoveHandler: 'del → unité Supprime un délégué d'écouteur d'un magasin d'écouteurs d'événements.

La section suivante fournit un exemple complet.

Exemple

L'exemple suivant montre le concept et les techniques discutés ci-dessus -

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"

Lorsque vous compilez et exécutez le programme, il produit la sortie suivante -

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!