F # - События

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

В графическом интерфейсе событиями являются действия пользователя, такие как нажатие клавиш, щелчки, движения мыши и т. Д., Или некоторые события, такие как уведомления, созданные системой. Приложениям необходимо реагировать на события, когда они происходят. Например, прерывания. События используются для межпроцессного взаимодействия.

Объекты общаются друг с другом посредством синхронной передачи сообщений.

События привязаны к другим функциям; реестр объектовcallback функции для события, и эти обратные вызовы выполняются, когда (и если) событие запускается каким-либо объектом.

Класс событий и модуль событий

Класс Control.Event <'T> помогает в создании наблюдаемого объекта или события.

У него есть следующие члены экземпляра для работы с событиями:

Член Описание
Публиковать Публикует наблюдение как первоклассную ценность.
Спусковой крючок Запускает наблюдение с использованием заданных параметров.

Модуль Control.Event предоставляет функции для управления потоками событий -

Значение Описание
добавить: ('T → unit) → Event <' Del, 'T> → unit Запускает заданную функцию каждый раз, когда запускается данное событие.
выберите: ('T →' U option) → IEvent <'Del,' T> → IEvent <'U> Возвращает новое событие, которое запускается при выборе сообщений из исходного события. Функция выбора преобразует исходное сообщение в необязательное новое сообщение.
фильтр: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> Возвращает новое событие, которое прослушивает исходное событие и запускает результирующее событие только тогда, когда аргумент события передает данную функцию.
карта: ('T →' U) → IEvent <'Del,' T> → IEvent <'U> Возвращает новое событие, которое передает значения, преобразованные данной функцией.
слияние: IEvent <'Del1,' T> → IEvent <'Del2,' T> → IEvent <'T> Запускает событие вывода, когда возникает одно из событий ввода.
попарно: IEvent <'Del,' T> → IEvent <'T *' T> Возвращает новое событие, которое запускается при втором и последующих запусках входного события. ВNth запуск входного события передает аргументы из N-1th и Nthзапускается как пара. Аргумент, переданный вN-1th запуск сохраняется в скрытом внутреннем состоянии до Nth происходит срабатывание.
раздел: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> * IEvent <'T> Возвращает новое событие, которое прослушивает исходное событие и запускает первое результирующее событие, если применение предиката к аргументам события вернуло истину, и второе событие, если оно вернуло ложь.
сканирование: ('U →' T → 'U) →' U → IEvent <'Del,' T> → IEvent <'U> Возвращает новое событие, состоящее из результатов применения данной функции накопления к последовательным значениям, инициированным для входного события. Элемент внутреннего состояния записывает текущее значение параметра состояния. Внутреннее состояние не заблокировано во время выполнения функции накопления, поэтому следует позаботиться о том, чтобы входной IEvent не запускался одновременно несколькими потоками.
split: ('T → Выбор <' U1, 'U2>) → IEvent <' Del, 'T> → IEvent <' U1> * IEvent <'U2> Возвращает новое событие, которое прослушивает исходное событие и запускает первое результирующее событие, если приложение функции к аргументам события вернуло Choice1Of2, и второе событие, если оно возвращает Choice2Of2.

Создание событий

События создаются и используются через Eventкласс. Конструктор событий используется для создания события.

пример

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

После этого вам необходимо предоставить поле nameChanged как публичный член, чтобы слушатели могли подключиться к событию, для которого вы используете Publish свойство события -

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

Затем вы добавляете обратные вызовы в обработчики событий. Каждый обработчик событий имеет тип IEvent <'T>, который предоставляет несколько методов:

Метод Описание
val Add: event :( 'T → unit) → unit Подключает функцию прослушивателя к событию. Слушатель будет вызываться при срабатывании события.
val AddHandler: 'del → unit Подключает объект делегата обработчика к событию. Позднее обработчик можно удалить с помощью RemoveHandler. Слушатель будет вызываться при срабатывании события.
val RemoveHandler: 'del → unit Удаляет делегата слушателя из хранилища слушателей событий.

В следующем разделе представлен полный пример.

пример

Следующий пример демонстрирует концепцию и методы, обсужденные выше.

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"

Когда вы компилируете и выполняете программу, она дает следующий результат:

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!