gebeurtenis
Met gebeurtenissen kunt u functieaanroepen koppelen aan gebruikersacties en zijn belangrijk in het programmeren van gui's. Gebeurtenissen kunnen ook worden geactiveerd door uw toepassingen of door het besturingssysteem.
Gebeurtenissen verwerken
Wanneer u een GUI-bibliotheek zoals Windows Forms of Windows Presentation Foundation (WPF) gebruikt, wordt veel van de code in uw toepassing uitgevoerd als reactie op gebeurtenissen die vooraf zijn gedefinieerd door de bibliotheek. Deze vooraf gedefinieerde gebeurtenissen zijn leden van GUI-klassen, zoals formulieren en besturingselementen. U kunt aangepast gedrag toevoegen aan een vooraf bestaande gebeurtenis, zoals klikken op een knop, door te verwijzen naar de specifieke benoemde gebeurtenis van belang (bijvoorbeeld de Click
gebeurtenis van de Form
klasse) en de Add
methode aan te roepen, zoals wordt weergegeven in de volgende code. Als u dit uitvoert vanuit F# Interactive, laat u de aanroep weg naar 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)
Het type van de Add
methode is ('a -> unit) -> unit
. Daarom gebruikt de gebeurtenis-handlermethode één parameter, meestal de gebeurtenisargumenten en retourneert unit
. In het vorige voorbeeld ziet u de gebeurtenis-handler als lambda-expressie. De gebeurtenis-handler kan ook een functiewaarde zijn, zoals in het volgende codevoorbeeld. In het volgende codevoorbeeld ziet u ook het gebruik van de parameters van de gebeurtenis-handler, die informatie bevatten die specifiek is voor het type gebeurtenis. Voor een MouseMove
gebeurtenis geeft het systeem een System.Windows.Forms.MouseEventArgs
object door, dat de X
en Y
positie van de aanwijzer bevat.
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)
Aangepaste gebeurtenissen maken
F#-gebeurtenissen worden vertegenwoordigd door het F# -gebeurtenistype , waarmee de IEvent-interface wordt geïmplementeerd. IEvent
is zelf een interface die de functionaliteit van twee andere interfaces combineert, System.IObservable<'T>
en IDelegateEvent. Event
Daarom hebben s de equivalente functionaliteit van gemachtigden in andere talen, plus de extra functionaliteit vanIObservable
, wat betekent dat F#-gebeurtenissen gebeurtenisfiltering ondersteunen en F#-functies en lambda-expressies gebruiken als gebeurtenis-handlers. Deze functionaliteit wordt geleverd in de gebeurtenismodule.
Als u een gebeurtenis wilt maken op een klasse die net als elke andere .NET Framework-gebeurtenis fungeert, voegt u een binding toe aan de klasse die let
een Event
als veld in een klasse definieert. U kunt het gewenste gebeurtenisargumenttype opgeven als het typeargument of leeg laten en de compiler het juiste type laten afleiden. U moet ook een gebeurtenislid definiëren dat de gebeurtenis beschikbaar maakt als EEN CLI-gebeurtenis. Dit lid moet het CLIEvent-kenmerk hebben. Het wordt gedeclareerd als een eigenschap en de implementatie ervan is slechts een aanroep van de eigenschap Publiceren van de gebeurtenis. Gebruikers van uw klasse kunnen de Add
methode van de gepubliceerde gebeurtenis gebruiken om een handler toe te voegen. Het argument voor de Add
methode kan een lambda-expressie zijn. U kunt de Trigger
eigenschap van de gebeurtenis gebruiken om de gebeurtenis te verhogen en de argumenten door te geven aan de handlerfunctie. In het volgende codevoorbeeld ziet u dit. In dit voorbeeld is het argument voor het afgeleid type voor de gebeurtenis een tuple, die de argumenten voor de lambda-expressie vertegenwoordigt.
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
De uitvoer is als volgt.
Event1 occurred! Object data: Hello World!
De aanvullende functionaliteit van de Event
module wordt hier geïllustreerd. Het volgende codevoorbeeld illustreert het basisgebruik van het maken van Event.create
een gebeurtenis en een triggermethode, het toevoegen van twee gebeurtenis-handlers in de vorm van lambda-expressies en het activeren van de gebeurtenis om beide lambda-expressies uit te voeren.
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.")
De uitvoer van de vorige code is als volgt.
Event occurred.
Given a value: Event occurred.
Gebeurtenisstromen verwerken
In plaats van alleen een gebeurtenishandler voor een gebeurtenis toe te voegen met behulp van de functie Event.add , kunt u de functies in de Event
module gebruiken om stromen van gebeurtenissen op zeer aangepaste manieren te verwerken. Hiervoor gebruikt u de doorstuurpijp (|>
) samen met de gebeurtenis als de eerste waarde in een reeks functie-aanroepen en fungeert de Event
module als volgende functie-aanroepen.
In het volgende codevoorbeeld ziet u hoe u een gebeurtenis instelt waarvoor de handler alleen onder bepaalde voorwaarden wordt aangeroepen.
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) )
De module Waarneembare bevat vergelijkbare functies die op waarneembare objecten werken. Waarneembare objecten zijn vergelijkbaar met gebeurtenissen, maar abonneren zich alleen actief op gebeurtenissen als ze zelf worden geabonneerd.
Een interface-gebeurtenis implementeren
Wanneer u ui-onderdelen ontwikkelt, begint u vaak met het maken van een nieuw formulier of een nieuw besturingselement dat wordt overgenomen van een bestaand formulier of besturingselement. Gebeurtenissen worden vaak gedefinieerd op een interface. In dat geval moet u de interface implementeren om de gebeurtenis te implementeren. De System.ComponentModel.INotifyPropertyChanged
interface definieert één System.ComponentModel.INotifyPropertyChanged.PropertyChanged
gebeurtenis. De volgende code illustreert hoe u de gebeurtenis implementeert die door deze overgenomen interface is gedefinieerd:
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)
Als u de gebeurtenis in de constructor wilt koppelen, is de code iets ingewikkelder omdat de gebeurtenishook in een then
blok in een extra constructor moet staan, zoals in het volgende voorbeeld:
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)