Partilhar via


evento

Os eventos permitem associar chamadas de função a ações do usuário e são importantes na programação GUI. Os eventos também podem ser acionados por seus aplicativos ou pelo sistema operacional.

Manipulação de eventos

Quando você usa uma biblioteca GUI como Windows Forms ou Windows Presentation Foundation (WPF), grande parte do código em seu aplicativo é executado em resposta a eventos que são predefinidos pela biblioteca. Esses eventos predefinidos são membros de classes GUI, como formulários e controles. Você pode adicionar um comportamento personalizado a um evento preexistente, como um clique no botão, fazendo referência ao evento nomeado específico de interesse (por exemplo, o Click evento da Form classe) e invocando o Add método, conforme mostrado no código a seguir. Se você executar isso a partir do F# interativo, omita a chamada para System.Windows.Forms.Application.Run(System.Windows.Forms.Form).

open System.Windows.Forms

let form = new Form(Text="F# Windows Form",
                    Visible = true,
                    TopMost = true)

form.Click.Add(fun evArgs -> System.Console.Beep())
Application.Run(form)

O tipo do Add método é ('a -> unit) -> unit. Portanto, o método manipulador de eventos usa um parâmetro, normalmente os argumentos de evento, e retorna unit. O exemplo anterior mostra o manipulador de eventos como uma expressão lambda. O manipulador de eventos também pode ser um valor de função, como no exemplo de código a seguir. O exemplo de código a seguir também mostra o uso dos parâmetros do manipulador de eventos, que fornecem informações específicas para o tipo de evento. Para um MouseMove evento, o sistema passa um System.Windows.Forms.MouseEventArgs objeto, que contém a X posição e Y do ponteiro.

open System.Windows.Forms

let Beep evArgs =
    System.Console.Beep( )


let form = new Form(Text = "F# Windows Form",
                    Visible = true,
                    TopMost = true)

let MouseMoveEventHandler (evArgs : System.Windows.Forms.MouseEventArgs) =
    form.Text <- System.String.Format("{0},{1}", evArgs.X, evArgs.Y)

form.Click.Add(Beep)
form.MouseMove.Add(MouseMoveEventHandler)
Application.Run(form)

Criação de eventos personalizados

Os eventos F# são representados pelo tipo de evento F#, que implementa a interface IEvent. IEvent é em si uma interface que combina a funcionalidade de duas outras interfaces System.IObservable<'T> e IDelegateEvent. Portanto, Events tem a funcionalidade equivalente a delegados em outros idiomas, além da funcionalidade adicional de , o que significa que os eventos F# suportam filtragem de eventos e usam funções de primeira classe F# e expressões lambda como manipuladores de IObservableeventos. Esta funcionalidade é fornecida no módulo Evento.

Para criar um evento em uma classe que age como qualquer outro evento do .NET Framework, adicione à classe uma let associação que define um Event como um campo em uma classe. Você pode especificar o tipo de argumento de evento desejado como o argumento type ou deixá-lo em branco e fazer com que o compilador infera o tipo apropriado. Você também deve definir um membro do evento que exponha o evento como um evento da CLI. Este membro deve ter o atributo CLIEvent . Ele é declarado como uma propriedade e sua implementação é apenas uma chamada para a propriedade Publish do evento. Os usuários de sua classe podem usar o Add método do evento publicado para adicionar um manipulador. O argumento para o Add método pode ser uma expressão lambda. Você pode usar a Trigger propriedade do evento para gerar o evento, passando os argumentos para a função manipulador. O exemplo de código a seguir ilustra isso. Neste exemplo, o argumento de tipo inferido para o evento é uma tupla, que representa os argumentos para a expressão lambda.

open System.Collections.Generic

type MyClassWithCLIEvent() =

    let event1 = new Event<string>()

    [<CLIEvent>]
    member this.Event1 = event1.Publish

    member this.TestEvent(arg) =
        event1.Trigger(arg)

let classWithEvent = new MyClassWithCLIEvent()
classWithEvent.Event1.Add(fun arg ->
        printfn "Event1 occurred! Object data: %s" arg)

classWithEvent.TestEvent("Hello World!")

System.Console.ReadLine() |> ignore

A saída é a seguinte.

Event1 occurred! Object data: Hello World!

A funcionalidade adicional fornecida pelo módulo é ilustrada Event aqui. O exemplo de código a seguir ilustra o uso básico de Event.create para criar um evento e um método de gatilho, adicionar dois manipuladores de eventos na forma de expressões lambda e, em seguida, acionar o evento para executar ambas as expressões lambda.

type MyType() =
    let myEvent = new Event<_>()

    member this.AddHandlers() =
       Event.add (fun string1 -> printfn "%s" string1) myEvent.Publish
       Event.add (fun string1 -> printfn "Given a value: %s" string1) myEvent.Publish

    member this.Trigger(message) =
       myEvent.Trigger(message)

let myMyType = MyType()
myMyType.AddHandlers()
myMyType.Trigger("Event occurred.")

A saída do código anterior é a seguinte.

Event occurred.
Given a value: Event occurred.

Processando fluxos de eventos

Em vez de apenas adicionar um manipulador de eventos para um evento usando a função Event.add , você pode usar as Event funções no módulo para processar fluxos de eventos de maneiras altamente personalizadas. Para fazer isso, use o pipe de encaminhamento (|>) juntamente com o evento como o primeiro valor de uma série de chamadas de função e o Event módulo funciona como chamadas de função subsequentes.

O exemplo de código a seguir mostra como configurar um evento para o qual o manipulador é chamado apenas sob determinadas condições.

let form = new Form(Text = "F# Windows Form",
                    Visible = true,
                    TopMost = true)
form.MouseMove
    |> Event.filter ( fun evArgs -> evArgs.X > 100 && evArgs.Y > 100)
    |> Event.add ( fun evArgs ->
        form.BackColor <- System.Drawing.Color.FromArgb(
            evArgs.X, evArgs.Y, evArgs.X ^^^ evArgs.Y) )

O módulo Observável contém funções semelhantes que operam em objetos observáveis. Os objetos observáveis são semelhantes a eventos, mas só se inscrevem ativamente em eventos se eles próprios estiverem sendo assinados.

Implementando um evento de interface

Ao desenvolver componentes da interface do usuário, você geralmente começa criando um novo formulário ou um novo controle que herda de um formulário ou controle existente. Os eventos são frequentemente definidos em uma interface e, nesse caso, você deve implementar a interface para implementar o evento. A System.ComponentModel.INotifyPropertyChanged interface define um único System.ComponentModel.INotifyPropertyChanged.PropertyChanged evento. O código a seguir ilustra como implementar o evento que essa interface herdada definiu:

module CustomForm

open System.Windows.Forms
open System.ComponentModel

type AppForm() as this =
    inherit Form()

    // Define the propertyChanged event.
    let propertyChanged = Event<PropertyChangedEventHandler, PropertyChangedEventArgs>()
    let mutable underlyingValue = "text0"

    // Set up a click event to change the properties.
    do
        this.Click |> Event.add(fun evArgs ->
            this.Property1 <- "text2"
            this.Property2 <- "text3")

    // This property does not have the property-changed event set.
    member val Property1 : string = "text" with get, set

    // This property has the property-changed event set.
    member this.Property2
        with get() = underlyingValue
        and set(newValue) =
            underlyingValue <- newValue
            propertyChanged.Trigger(this, new PropertyChangedEventArgs("Property2"))

    // Expose the PropertyChanged event as a first class .NET event.
    [<CLIEvent>]
    member this.PropertyChanged = propertyChanged.Publish

    // Define the add and remove methods to implement this interface.
    interface INotifyPropertyChanged with
        member this.add_PropertyChanged(handler) = propertyChanged.Publish.AddHandler(handler)
        member this.remove_PropertyChanged(handler) = propertyChanged.Publish.RemoveHandler(handler)

    // This is the event-handler method.
    member this.OnPropertyChanged(args : PropertyChangedEventArgs) =
        let newProperty = this.GetType().GetProperty(args.PropertyName)
        let newValue = newProperty.GetValue(this :> obj) :?> string
        printfn "Property {args.PropertyName} changed its value to {newValue}"

// Create a form, hook up the event handler, and start the application.
let appForm = new AppForm()
let inpc = appForm :> INotifyPropertyChanged
inpc.PropertyChanged.Add(appForm.OnPropertyChanged)
Application.Run(appForm)

Se você quiser conectar o evento no construtor, o código é um pouco mais complicado porque a conexão de evento deve estar em um then bloco em um construtor adicional, como no exemplo a seguir:

module CustomForm

open System.Windows.Forms
open System.ComponentModel

// Create a private constructor with a dummy argument so that the public
// constructor can have no arguments.
type AppForm private (dummy) as this =
    inherit Form()

    // Define the propertyChanged event.
    let propertyChanged = Event<PropertyChangedEventHandler, PropertyChangedEventArgs>()
    let mutable underlyingValue = "text0"

    // Set up a click event to change the properties.
    do
        this.Click |> Event.add(fun evArgs ->
            this.Property1 <- "text2"
            this.Property2 <- "text3")

    // This property does not have the property changed event set.
    member val Property1 : string = "text" with get, set

    // This property has the property changed event set.
    member this.Property2
        with get() = underlyingValue
        and set(newValue) =
            underlyingValue <- newValue
            propertyChanged.Trigger(this, new PropertyChangedEventArgs("Property2"))

    [<CLIEvent>]
    member this.PropertyChanged = propertyChanged.Publish

    // Define the add and remove methods to implement this interface.
    interface INotifyPropertyChanged with
        member this.add_PropertyChanged(handler) = this.PropertyChanged.AddHandler(handler)
        member this.remove_PropertyChanged(handler) = this.PropertyChanged.RemoveHandler(handler)

    // This is the event handler method.
    member this.OnPropertyChanged(args : PropertyChangedEventArgs) =
        let newProperty = this.GetType().GetProperty(args.PropertyName)
        let newValue = newProperty.GetValue(this :> obj) :?> string
        printfn "Property {args.PropertyName} changed its value to {newValue}"

    new() as this =
        new AppForm(0)
        then
            let inpc = this :> INotifyPropertyChanged
            inpc.PropertyChanged.Add(this.OnPropertyChanged)

// Create a form, hook up the event handler, and start the application.
let appForm = new AppForm()
Application.Run(appForm)

Consulte também