Поделиться через


События (F#)

События позволяют связывать вызовы функций с действиями пользователя и являются важным элементом в программировании графического интерфейса пользователя. События могут также инициироваться приложениями или операционной системой.

Обработка событий

При использовании библиотеки графического интерфейса пользователя, такой как Windows Forms или Windows Presentation Foundation (WPF), значительная часть кода в приложении выполняется в ответ на события, предопределенные в библиотеке. Эти предопределенные события являются членами классов графического интерфейса пользователя, таких как формы и элементы управления. Можно добавить произвольное поведение к уже существующему событию, такому как нажатие кнопки, сославшись на интересующее именованное событие (например, событие Click класса Form) и вызвав метод Add, как показано в следующем коде. При запуске этого кода из F# Interactive вызов метода Run следует опустить.

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)

Тип метода Add — ('a -> unit) -> unit. Следовательно, метод, обрабатывающий событие, принимает один параметр — обычно аргументы события — и возвращает значение типа unit. В предыдущем примере обработчик события показан как лямбда-выражение. Обработчик события также может представлять собой значение функции, как в следующем примере кода. В следующем примере кода также показано использование параметров обработчика события, содержащих данные, зависящие от типа события. Для события MouseMove система передает объект MouseEventArgs, содержащий координаты X и Y положения указателя.

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)

Создание пользовательских событий

События в языке F# представлены классом Event языка F#, реализующим интерфейс IEvent. IEvent представляет собой интерфейс, объединяющий функциональные возможности двух других интерфейсов, IObservable<T> и IDelegateEvent. Следовательно, события Event обладают функциональными возможностями, эквивалентными возможностям делегатов в других языках, и дополнительно функциональными возможностями интерфейса IObservable; это означает, что события F# поддерживают фильтрацию событий и использование функций первого класса и лямбда-выражений языка F# в качестве обработчиков событий. Эти функциональные возможности обеспечиваются модулем Event.

Чтобы создать для класса событие, которое ведет себя точно так же, как любое другое событие платформы .NET Framework, добавьте в класс привязку let, определяющую событие Event как поле в классе. В качестве аргумента типа можно указать требуемый тип аргумента события или оставить его пустым, чтобы соответствующий тип был выведен компилятором. Необходимо также определить член события, предоставляющего это событие как событие CLI. Этот член должен иметь атрибут CLIEvent. Он объявляется как свойство, и его реализация представляет собой просто вызов свойства Publish события. Пользователи класса могут использовать метод Add опубликованного события для добавления обработчика. Аргумент метода Add может быть лямбда-выражением. Для вызова события можно использовать свойство Trigger события, передавая аргумент функции-обработчику. Это показано в следующем примере кода. В этом примере выведенный аргумент типа для события — кортеж, представляющий аргументы для лямбда-выражения.

open System.Collections.Generic

type MyClassWithCLIEvent() =

    let event1 = new Event<_>()

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

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

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

classWithEvent.TestEvent("Hello World!")

System.Console.ReadLine() |> ignore

Выходные данные выглядят следующим образом.

Event1 occurred! Object data: Hello World!

Здесь иллюстрируется дополнительная функциональная возможность, обеспечиваемая модулем Event. Следующий пример кода иллюстрирует основное использование функции Event.create для создания события и метода-триггера, добавления двух обработчиков события в виде лямбда-выражений и последующего инициирования события для выполнения обоих лямбда-выражений.

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.")

Результат выполнения приведенного кода будет следующим.

Event occurred.
Given a value: Event occurred.

Обработка потоков событий

Вместо простого добавления обработчика события для события с помощью функции Event.add можно использовать функции в модуле Event для обработки потоков событий настраиваемыми способами. Это делается путем использования оператора прямого конвейера (|>) вместе с событием в качестве первого значения в серии вызовов функций и функций модуля Event в качестве последующих вызовов функций.

В следующем примере кода демонстрируется, как настроить событие, обработчик которого вызывается только при определенных условиях.

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

Модуль Observable содержит аналогичные функции, действующие на наблюдаемые объекты. Наблюдаемые объекты аналогичны событиям, но они активно подписываются на события только при создании подписки на такой объект.

См. также

Ссылки

Лямбда-выражения: ключевое слово fun (F#)

Модуль Control.Event (F#)

Класс Control.Event<'T> (F#)

Класс Control.Event<'Delegate,'Args> (F#)

Основные понятия

Члены (F#)

События и делегаты

Журнал изменений

Дата

Журнал

Причина

Январь 2011

Сделано ударение на использовании класса Event вместо класса DelegateEvent.

Улучшение информации.