F # - Eventos

Os eventos permitem que as turmas enviem e recebam mensagens entre si.

Na GUI, os eventos são ações do usuário como pressionamento de tecla, cliques, movimentos do mouse, etc., ou alguma ocorrência como notificações geradas pelo sistema. Os aplicativos precisam responder aos eventos quando eles ocorrem. Por exemplo, interrupções. Os eventos são usados ​​para comunicação entre processos.

Os objetos comunicam-se uns com os outros através da passagem síncrona de mensagens.

Os eventos são anexados a outras funções; registro de objetoscallback funções para um evento, e esses retornos de chamada são executados quando (e se) o evento é disparado por algum objeto.

A classe de evento e o módulo de evento

A classe Control.Event <'T> ajuda a criar um objeto ou evento observável.

Tem os seguintes membros de instância para trabalhar com os eventos -

Membro Descrição
Publicar Publica uma observação como um valor de primeira classe.
Desencadear Dispara uma observação usando os parâmetros fornecidos.

O Módulo Control.Event fornece funções para gerenciar fluxos de eventos -

Valor Descrição
adicione: ('T → unidade) → Evento <' Del, 'T> → unidade Executa a função fornecida sempre que um determinado evento é disparado.
escolha: ('T →' opção U) → IEvent <'Del,' T> → IEvent <'U> Retorna um novo evento que dispara em uma seleção de mensagens do evento original. A função de seleção leva uma mensagem original a uma nova mensagem opcional.
filtro: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> Retorna um novo evento que escuta o evento original e dispara o evento resultante apenas quando o argumento para o evento passa pela função fornecida.
mapa: ('T →' U) → IEvent <'Del,' T> → IEvent <'U> Retorna um novo evento que passa valores transformados pela função fornecida.
mesclar: IEvent <'Del1,' T> → IEvent <'Del2,' T> → IEvent <'T> Dispara o evento de saída quando um dos eventos de entrada é disparado.
em pares: IEvent <'Del,' T> → IEvent <'T *' T> Retorna um novo evento que dispara no segundo disparo e nos subsequentes do evento de entrada. oNth o acionamento do evento de entrada passa os argumentos do N-1th e Nthdesencadeando como um par. O argumento passou para oN-1th o acionamento é mantido em estado interno oculto até que o Nth o acionamento ocorre.
partição: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> * IEvent <'T> Retorna um novo evento que escuta o evento original e dispara o primeiro evento resultante se a aplicação do predicado aos argumentos do evento retornou verdadeiro, e o segundo evento se retornou falso.
varredura: ('U →' T → 'U) →' U → IEvent <'Del,' T> → IEvent <'U> Retorna um novo evento que consiste nos resultados da aplicação da função de acumulação fornecida a valores sucessivos acionados no evento de entrada. Um item de estado interno registra o valor atual do parâmetro de estado. O estado interno não é bloqueado durante a execução da função de acumulação, portanto, deve-se tomar cuidado para que a entrada IEvent não seja acionada por vários threads simultaneamente.
dividir: ('T → Escolha <' U1, 'U2>) → IEvent <' Del, 'T> → IEvent <' U1> * IEvent <'U2> Retorna um novo evento que escuta o evento original e dispara o primeiro evento resultante se a aplicação da função aos argumentos do evento retornou um Choice1Of2, e o segundo evento se ele retornou um Choice2Of2.

Criação de eventos

Os eventos são criados e usados ​​por meio do Eventclasse. O construtor Event é usado para criar um evento.

Exemplo

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

Depois disso, você precisa expor o campo nameChanged como um membro público, para que os ouvintes possam se conectar ao evento para o qual você usa o Publish propriedade do evento -

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

Em seguida, você adiciona retornos de chamada aos manipuladores de eventos. Cada manipulador de eventos tem o tipo IEvent <'T>, que fornece vários métodos -

Método Descrição
val Adicionar: evento :( 'T → unidade) → unidade Conecta uma função de ouvinte ao evento. O listener será invocado quando o evento for disparado.
val AddHandler: 'del → unidade Conecta um objeto delegado do manipulador ao evento. Um manipulador pode ser removido posteriormente usando RemoveHandler. O listener será invocado quando o evento for disparado.
val RemoveHandler: 'del → unidade Remove um delegado de ouvinte de um armazenamento de ouvinte de evento.

A seção a seguir fornece um exemplo completo.

Exemplo

O exemplo a seguir demonstra o conceito e as técnicas discutidas acima -

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"

Quando você compila e executa o programa, ele produz a seguinte saída -

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!