Acara
Kejadian memungkinkan Anda untuk mengasosiasikan panggilan fungsi dengan tindakan pengguna dan merupakan hal penting dalam pemrograman GUI. Kejadian juga dapat dipicu oleh aplikasi Anda atau oleh sistem operasi.
Menangani Peristiwa
Saat Anda menggunakan pustaka GUI seperti Formulir Windows atau Windows Presentation Foundation (WPF), sebagian besar kode di aplikasi Anda berjalan sebagai respons terhadap kejadian yang telah ditentukan sebelumnya oleh pustaka. Kejadian yang telah ditentukan sebelumnya ini merupakan anggota dari kelas GUI, seperti formulir dan kontrol. Anda dapat menambahkan perilaku kustom ke kejadian yang sudah ada sebelumnya, seperti klik tombol, dengan merujuk ke kejadian tertentu yang disebut menarik (misalnya, kejadian Click
kelas Form
) dan memanggil metode Add
, seperti yang ditunjukkan dalam kode berikut. Jika Anda menjalankan ini dari F# Interactive, hapus panggilan ke System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
.
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)
Jenis metode Add
adalah ('a -> unit) -> unit
. Oleh karena itu, metode penanganan aktivitas mengambil satu parameter, biasanya adalah argumen kejadian, dan mengembalikan unit
. Contoh sebelumnya menunjukkan penanganan aktivitas sebagai ekspresi lambda. Penanganan aktivitas juga dapat berupa nilai fungsi, seperti dalam contoh kode berikut. Contoh kode berikut juga menunjukkan penggunaan parameter penanganan aktivitas, yang memberikan informasi khusus untuk jenis kejadian. Untuk kejadian MouseMove
, sistem meneruskan objek System.Windows.Forms.MouseEventArgs
, yang berisi posisi X
dan Y
pointer.
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)
Membuat Kejadian Kustom
Kejadian F# diwakili oleh jenis Kejadian F#, yang mengimplementasikan antarmuka IEvent. IEvent
sendiri adalah antarmuka yang menggabungkan fungsionalitas dua antarmuka lainnya, yaitu System.IObservable<'T>
dan IDelegateEvent. Oleh karena itu, Event
memiliki fungsionalitas delegasi yang setara dalam bahasa pemrograman lain, ditambah fungsionalitas tambahan dari IObservable
, yang berarti bahwa kejadian F# mendukung pemfilteran kejadian dan menggunakan fungsi kelas satu F# dan ekspresi lambda sebagai penanganan aktivitas. Fungsionalitas ini disediakan dalam modul Kejadian.
Untuk membuat kejadian pada kelas yang bertindak sama seperti kejadian .NET Framework lainnya, tambahkan ke kelas tersebut pengikatan let
yang mendefinisikan Event
sebagai bidang dalam sebuah kelas. Anda dapat menentukan jenis argumen kejadian yang diinginkan sebagai argumen jenis, atau biarkan kosong dan buat kompilator menyimpulkan jenis yang sesuai. Anda juga harus menentukan anggota kejadian yang mengekspos kejadian sebagai kejadian CLI. Anggota ini harus memiliki atribut CLIEvent. Anggota tersebut dideklarasikan seperti properti dan implementasinya hanyalah panggilan ke properti Terbitkan dari kejadian tersebut. Pengguna kelas Anda dapat menggunakan metode Add
dari kejadian yang diterbitkan untuk menambahkan penangan. Argumen untuk metode Add
dapat berupa ekspresi lambda. Anda dapat menggunakan properti Trigger
acara untuk menaikkan kejadian, meneruskan argumen ke fungsi penangan. Contoh kode berikut menggambarkan hal ini. Dalam contoh ini, argumen jenis yang disimpulkan untuk kejadian adalah tuple, yang mewakili argumen untuk ekspresi lambda.
open System.Collections.Generic
type MyClassWithCLIEvent() =
let event1 = new Event<string>()
[<CLIEvent>]
member this.Event1 = event1.Publish
member this.TestEvent(arg) =
event1.Trigger(arg)
let classWithEvent = new MyClassWithCLIEvent()
classWithEvent.Event1.Add(fun arg ->
printfn "Event1 occurred! Object data: %s" arg)
classWithEvent.TestEvent("Hello World!")
System.Console.ReadLine() |> ignore
Outputnya sebagai berikut.
Event1 occurred! Object data: Hello World!
Fungsionalitas tambahan yang disediakan oleh modul Event
digambarkan di sini. Contoh kode berikut menggambarkan penggunaan dasar Event.create
untuk membuat sebuah kejadian dan metode pemicu, menambahkan dua penanganan aktivitas dalam formulir ekspresi lambda, kemudian memicu kejadian untuk menjalankan kedua ekspresi 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.")
Output dari kode sebelumnya adalah seperti berikut.
Event occurred.
Given a value: Event occurred.
Memproses Aliran Kejadian
Alih-alih hanya menambahkan penanganan aktivitas untuk kejadian dengan menggunakan fungsi Event.add, Anda dalam menggunakan fungsi di modul Event
untuk memproses aliran kejadian dengan cara yang sangat disesuaikan. Untuk melakukan ini, Anda menggunakan pipa teruskan (|>
) bersama dengan kejadian sebagai nilai pertama dalam serangkaian panggilan fungsi, dan fungsi modul Event
sebagai panggilan fungsi berikutnya.
Contoh kode berikut menunjukkan cara untuk menyiapkan kejadian yang dipanggil penangan hanya dalam kondisi tertentu.
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) )
Modul yang dapat diamati berisi fungsi serupa yang beroperasi pada objek yang dapat diamati. Objek yang dapat diamati mirip dengan kejadian, tetapi hanya berlangganan secara aktif ke kejadian jika mereka sendiri dijadikan langganan.
Menerapkan Kejadian Antarmuka
Saat Anda mengembangkan komponen antarmuka pengguna, Anda sering memulai dengan membuat formulir baru atau kontrol baru yang mewarisi dari formulir atau kontrol yang ada. Kejadian sering didefinisikan pada antarmuka, dan, dalam hal ini, Anda harus mengimplementasikan antarmuka untuk mengimplementasikan kejadian. Antarmuka System.ComponentModel.INotifyPropertyChanged
mendefinisikan kejadian System.ComponentModel.INotifyPropertyChanged.PropertyChanged
tunggal. Kode berikut menggambarkan cara mengimplementasikan kejadian yang ditentukan oleh antarmuka yang diwariskan ini:
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 {args.PropertyName} changed its value to {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)
Jika Anda ingin menghubungkan kejadian di konstruktor, kodenya akan sedikit lebih rumit karena hubungan kejadian harus berada di blok then
di konstruktor tambahan, seperti dalam contoh berikut:
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 {args.PropertyName} changed its value to {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)