事件使您能够将函数调用与用户操作而是重要在 GUI 编程。事件也可以触发应用程序或操作系统。
处理事件
当您使用诸如 windows 窗体或 windows presentation foundation 之类的 GUI 库 (WPF)时,应用程序中的大部分代码运行以响应由库预定义事件。这些预定义事件是 GUI 类的成员 (例如窗体和控件。可以将自定义行为到预先存在的操作,例如单击按钮,通过引用有意义的特定命名事件 (例如, Form 类的 Click 事件) 并调用 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。前面的示例显示了 lambda 表达式形式的事件处理程序事件处理程序也可以为函数值,如下面的代码示例所示。下面的代码示例还显示了事件处理程序参数,提供特定于事件类型的信息。为 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# 事件由 F# 事件 类表示,该类可实现 IEvent 接口。IEvent 本身合并两个其他接口、 IObservable<T> 和 IDelegateEvent功能的接口。因此, Event的具有委托的同等功能在其他语言,以及从 IObservable的附加功能,这意味着, F# 事件支持筛选并使用 F# 第一类函数和 lambda 表达式作为事件处理程序。此函数在 事件模块提供。
若要创建在象任何其他 .NET framework 事件的类中的事件,请添加到类定义 Event 作为类的一个字段的一 let 绑定。可以指定所需的事件参数类型为类型参数,或将其保留为空白让编译器推断适当的类型。还必须定义一个事件作为 CLI 事件的事件成员。此成员应具有 CLIEvent 属性。声明它与属性类似,并且其实现是调用该事件的 发布 属性。您的类的用户可以使用已发布事件的 Add 方法来添加处理程序。Add 方法的参数可以是 lambda 表达式。可以使用事件的 Trigger 属性引发事件,以便将参数传递给处理程序函数。下面的代码示例阐释了这一点。在此示例中,事件的推断类型参数是一个元组,表示 lambda 表达式的参数。
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 模块提供的附加功能此处说明。以 lambda 表达式的形式,下面的代码示例阐释 Event.create 的基本使用创建事件和触发器方法,添加两个事件处理程序,然后触发事件执行两个 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.")
上述代码的输出结果如下。
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) )
可观测模块 包含对可观测对象的类似功能。,如果它们订阅,可观测对象与事件类似,但时才会主动订阅事件。
实现接口事件
在开发 UI 元素,则可以通过创建新窗体或从现有窗体或控件继承的新控件通常启动。事件在界面经常定义,,因此,在这种情况下,必须实现接口实现事件。INotifyPropertyChanged 接口定义一个 PropertyChanged 事件。下面的代码演示如何实现此继承的接口定义的事件:
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 %s changed its value to %s" args.PropertyName 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)
如果要安装在构造函数的事件,代码较为复杂,因为事件挂接在其他构造函数必须在 then 块,如下面的示例所示:
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 %s changed its value to %s" args.PropertyName 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)
请参见
参考
Control.Event<'Delegate,'Args> 类 (F#)