事件允许类之间相互发送和接收消息,对象通过同步消息传递相互通信。

事件类和事件模块

Control.Event <'T>类有助于创建可观察的对象或事件。

Member 说明
Publish 将观察输出作为一等值发布。
Trigger 使用给定的参数触发观察。

Control.Event模块提供用于管理事件流的功能-

Value 描述
add : ('T → unit) → Event<'Del,'T> → unit 每次触发给定事件时运行给定函数。
choose : ('T → 'U option) → IEvent<'Del,'T> → IEvent<'U> 返回一个新事件,该事件在从原始事件中选择的消息上触发。选择功能将原始消息带到可选的新消息中。
filter : ('T → bool) → IEvent<'Del,'T> → IEvent<'T> 返回一个新事件,该事件侦听原始事件并仅在事件的参数传递给定函数时才触发结果事件。
map : ('T → 'U) → IEvent<'Del, 'T> → IEvent<'U> 返回一个新事件,该事件传递由给定函数转换的值。
merge : IEvent<'Del1,'T> → IEvent<'Del2,'T> → IEvent<'T> 当任一输入事件触发时,触发输出事件。
pairwise : IEvent<'Del,'T> → IEvent<'T * 'T> 返回一个新事件,该事件在输入事件的第二次和后续触发时触发。输入事件的第N次触发将成对的第N-1次触发和第N次触发的参数传递。传递给第N-1次触发的参数将保持隐藏的内部状态,直到发生第N次触发为止。
partition : ('T → bool) → IEvent<'Del,'T> → IEvent<'T> * IEvent<'T> 如果谓词对事件参数的应用返回true,则返回侦听原始事件并触发第一个结果事件的新事件,如果第二个事件返回false,则触发新的事件。
scan : ('U → 'T → 'U) → 'U → IEvent<'Del,'T> → IEvent<'U> 返回一个新事件,该事件包括将给定累加函数应用于输入事件上触发的连续值的结果。内部状态项记录状态参数的当前值。在执行累积函数期间,内部状态未锁定,因此应注意不要同时由多个线程触发输入IEvent。
split : ('T → Choice<'U1,'U2>) → IEvent<'Del,'T> → IEvent<'U1> * IEvent<'U2> 如果该函数对事件参数的应用返回了Choice1Of2,则返回一个侦听原始事件并触发第一个结果事件的新事件,如果第二个事件返回Choice2Of2,则触发该事件。

创建事件

事件是通过 Event 类创建和使用的, 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!

参考链接

https://www.learnfk.com/fsharp/fsharp-events.html