esemény
Az események lehetővé teszik a függvényhívások felhasználói műveletekhez való társításához, és fontosak a grafikus felhasználói felület programozásában. Az eseményeket az alkalmazások vagy az operációs rendszer is kiválthatja.
Események kezelése
Ha olyan grafikus felhasználói felületi kódtárat használ, mint a Windows Forms vagy a Windows megjelenítési alaprendszer (WPF), az alkalmazásban lévő kód nagy része a kódtár által előre definiált eseményekre reagálva fut. Ezek az előre definiált események a grafikus felhasználói felület osztályainak tagjai, például űrlapok és vezérlők. Egyéni viselkedést adhat hozzá egy már létező eseményhez, például egy gombkattintáshoz, ha hivatkozik az adott nevesített eseményre (például Click
az Form
osztály eseményére) és a metódus meghívására Add
, ahogyan az az alábbi kódban látható. Ha ezt az F# Interactive-ból futtatja, hagyja ki a hívást 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)
A metódus típusa a Add
következő ('a -> unit) -> unit
: . Ezért az eseménykezelő metódus egy paramétert vesz fel, általában az eseményargumentumokat, és visszaadja a függvényt unit
. Az előző példában az eseménykezelő lambda kifejezésként jelenik meg. Az eseménykezelő függvényérték is lehet, ahogyan az alábbi kód példában is látható. Az alábbi kód példája az eseménykezelő paraméterek használatát is mutatja, amelyek az esemény típusára vonatkozó információkat tartalmaznak. Esemény esetén MouseMove
a rendszer átad egy System.Windows.Forms.MouseEventArgs
objektumot, amely tartalmazza a X
mutató helyét és Y
helyét.
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)
Egyéni események létrehozása
Az F#-eseményeket az F# eseménytípus jelöli, amely implementálja az IEvent felületet. IEvent
maga egy felület, amely két másik interfész és az IDelegateEvent funkcióit System.IObservable<'T>
egyesíti. Ezért a meghatalmazottak más nyelveken is egyenértékű funkcióval rendelkeznek, valamint a további funkciókkalIObservable
, ami azt jelenti, Event
hogy az F#-események támogatják az eseményszűréseket, és az F# első osztályú függvényeket és lambda-kifejezéseket használják eseménykezelőként. Ez a funkció az Esemény modulban érhető el.
Ha olyan eseményt szeretne létrehozni egy osztályon, amely ugyanúgy működik, mint bármely más .NET-keretrendszer esemény, adjon hozzá az osztályhoz egy let
olyan kötéstEvent
, amely egy osztály mezőjeként definiál. Típusargumentumként megadhatja a kívánt eseményargumentumtípust, vagy üresen hagyhatja, és a fordító a megfelelő típusra következtethet. Meg kell határoznia egy olyan eseménytagot is, amely cli-eseményként teszi elérhetővé az eseményt. Ennek a tagnak rendelkeznie kell a CLIEvent attribútummal. Tulajdonságként van deklarálva, és megvalósítása csak az esemény Publish tulajdonságának hívása. Az osztály felhasználói a Add
közzétett esemény metódusával adhatnak hozzá kezelőt. A metódus argumentuma Add
lehet lambda kifejezés. Az esemény tulajdonságával emelheti az eseményt, és átadhatja Trigger
az argumentumokat a kezelőfüggvénynek. Az alábbi példakód ezt szemlélteti. Ebben a példában az esemény kikövetkeztetett típusargumentuma egy rekord, amely a lambda kifejezés argumentumait jelöli.
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
A kimenet a következő.
Event1 occurred! Object data: Hello World!
A modul által Event
biztosított további funkciókat itt találja. Az alábbi példakód bemutatja egy esemény és egy triggermetódus létrehozásának alapszintű használatát Event.create
, két eseménykezelő hozzáadását lambdakifejezések formájában, majd aktiválja az eseményt mindkét lambda-kifejezés végrehajtásához.
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.")
Az előző kód kimenete a következő.
Event occurred.
Given a value: Event occurred.
Eseményfeldolgozási adatfolyamok
Ahelyett, hogy az Event.add függvény használatával egyszerűen hozzáad egy eseménykezelőt egy eseményhez, a modul funkcióival nagymértékben testre szabott módon dolgozhatja fel az Event
eseményfolyamokat. Ehhez a továbbítási csövet (|>
) és az eseményt fogja használni a függvényhívások sorozatának első értékeként, a modul pedig Event
függvényhívásokként működik.
Az alábbi példakód bemutatja, hogyan állíthat be olyan eseményt, amelyhez a kezelő csak bizonyos feltételek mellett van meghívva.
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) )
Az Megfigyelhető modul hasonló függvényeket tartalmaz, amelyek megfigyelhető objektumokon működnek. A megfigyelhető objektumok hasonlóak az eseményekhez, de csak akkor iratkoznak fel aktívan az eseményekre, ha maguk is előfizetnek rájuk.
Interfészesemény implementálása
A felhasználói felület összetevőinek fejlesztése során gyakran egy új űrlap vagy egy meglévő űrlapból vagy vezérlőelemből öröklő új vezérlő létrehozásával kezdi. Az események gyakran vannak definiálva egy felületen, és ebben az esetben implementálnia kell a felületet az esemény megvalósításához. A System.ComponentModel.INotifyPropertyChanged
felület egyetlen System.ComponentModel.INotifyPropertyChanged.PropertyChanged
eseményt határoz meg. Az alábbi kód bemutatja, hogyan implementálható az öröklött felület által definiált esemény:
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)
Ha az eseményt a konstruktorban szeretné csatlakoztatni, a kód egy kicsit bonyolultabb, mert az eseménycsatlakozásnak egy then
blokkban kell lennie egy további konstruktorban, ahogyan az alábbi példában is látható:
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)