F# - 事件


事件允许类之间发送和接收消息。

在 GUI 中,事件是用户操作,如按键、单击、鼠标移动等,或某些事件,如系统生成的通知。应用程序需要在事件发生时做出响应。例如,中断。事件用于进程间通信。

对象通过同步消息传递来相互通信。

事件附属于其他函数;对象向事件注册回调函数,并且当(并且如果)某个对象触发事件时执行这些回调。

事件类和事件模块

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

它有以下实例成员来处理事件 -

成员 描述
发布 将观察结果发布为一流值。
扳机 使用给定参数触发观察。

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

价值 描述
添加 : ('T → 单位) → 事件<'Del,'T> → 单位 每次触发给定事件时运行给定函数。
选择:('T → 'U 选项)→ 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> 返回一个新事件,该事件在第二次及后续触发输入事件时触发。输入事件的第N 次触发将第 N-1 次第 N 次触发的参数作为一对传递。传递给第 N-1 次触发的参数将保持在隐藏的内部状态,直到第N 次触发发生。
分区 : ('T → bool) → IEvent<'Del,'T> → IEvent<'T> * IEvent<'T> 返回一个新事件,该事件侦听原始事件,如果对事件参数的谓词应用返回 true,则触发第一个结果事件;如果返回 false,则触发第二个事件。
扫描:('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 添加 : 事件:('T → 单位) → 单位 将侦听器函数连接到事件。事件触发时将调用侦听器。
val AddHandler : 'del → 单元 将处理程序委托对象连接到事件。稍后可以使用RemoveHandler 删除处理程序。事件触发时将调用侦听器。
val RemoveHandler : 'del → 单元 从事件侦听器存储中删除侦听器委托。

以下部分提供了一个完整的示例。

例子

以下示例演示了上面讨论的概念和技术 -

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!