Sdílet prostřednictvím


Události

Události umožňují přidružit volání funkcí k uživatelským akcím a jsou důležité při programování grafického uživatelského rozhraní. Události můžou aktivovat také vaše aplikace nebo operační systém.

Zpracování událostí

Pokud používáte knihovnu grafického uživatelského rozhraní, jako je Windows Forms nebo Windows Presentation Foundation (WPF), spustí se většina kódu ve vaší aplikaci v reakci na události, které jsou předdefinované knihovnou. Tyto předdefinované události jsou členy tříd grafického uživatelského rozhraní, jako jsou formuláře a ovládací prvky. Vlastní chování můžete přidat k existující události, například kliknutí na tlačítko, odkazem na konkrétní pojmenovanou událost zájmu (například Click událost Form třídy) a vyvoláním metody, jak je znázorněno Add v následujícím kódu. Pokud to spustíte z F# Interactive, vynecháte volání 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)

Typ Add metody je ('a -> unit) -> unit. Proto metoda obslužné rutiny události přebírá jeden parametr, obvykle argumenty události a vrací unit. Předchozí příklad ukazuje obslužnou rutinu události jako výraz lambda. Obslužná rutina události může být také hodnotou funkce, jako v následujícím příkladu kódu. Následující příklad kódu také ukazuje použití parametrů obslužné rutiny události, které poskytují informace specifické pro typ události. MouseMove V případě události systém předá System.Windows.Forms.MouseEventArgs objekt, který obsahuje X a Y pozici ukazatele.

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)

Vytváření vlastních událostí

Události jazyka F# jsou reprezentovány typem události jazyka F#, který implementuje rozhraní IEvent . IEvent je sám o sobě rozhraní, které kombinuje funkce dvou dalších rozhraní a System.IObservable<'T>IDelegateEvent. EventProto mají ekvivalentní funkce delegátů v jiných jazycích a další funkce z IObservable, což znamená, že události jazyka F# podporují filtrování událostí a používají funkce první třídy jazyka F# a výrazy lambda jako obslužné rutiny událostí. Tato funkce je k dispozici v modulu událostí.

Chcete-li vytvořit událost třídy, která funguje stejně jako jakákoli jiná událost rozhraní .NET Framework, přidejte do třídy let vazbu, která definuje Event jako pole ve třídě. Požadovaný typ argumentu události můžete zadat jako argument typu, nebo ho nechat prázdný a nechat kompilátor odvozen odpovídající typ. Musíte také definovat člena události, který událost zveřejňuje jako událost rozhraní příkazového řádku. Tento člen by měl mít atribut CLIEvent . Deklaruje se jako vlastnost a její implementace je pouze volání vlastnosti Publish události. Uživatelé vaší třídy mohou použít Add metodu publikované události k přidání obslužné rutiny. Argumentem Add metody může být výraz lambda. Vlastnost události můžete použít Trigger k vyvolání události a předání argumentů funkci obslužné rutiny. Následující příklad kódu to ilustruje. V tomto příkladu je odvozený argument typu pro událost řazenou kolekcí členů, který představuje argumenty výrazu 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

Výstup je následující.

Event1 occurred! Object data: Hello World!

Další funkce poskytované modulem Event jsou zde znázorněny. Následující příklad kódu znázorňuje základní použití Event.create k vytvoření události a metody triggeru, přidání dvou obslužných rutin událostí ve formě výrazů lambda a následné aktivaci události pro spuštění obou výrazů 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.")

Výstup předchozího kódu je následující.

Event occurred.
Given a value: Event occurred.

Zpracování streamů událostí

Místo pouhého přidání obslužné rutiny události pro událost pomocí funkce Event.add můžete pomocí funkcí v Event modulu zpracovávat streamy událostí vysoce přizpůsobenými způsoby. K tomu použijete předávací kanál (|>) společně s událostí jako první hodnotu v řadě volání funkcí a Event modul funkce jako následná volání funkce.

Následující příklad kódu ukazuje, jak nastavit událost, pro kterou je obslužná rutina volána pouze za určitých podmínek.

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 Observable obsahuje podobné funkce, které pracují s pozorovatelnými objekty. Pozorovatelné objekty se podobají událostem, ale aktivně se přihlašují k odběru událostí, pokud se samy přihlašují k odběru.

Implementace události rozhraní

Při vývoji součástí uživatelského rozhraní často začínáte vytvořením nového formuláře nebo nového ovládacího prvku, který dědí z existujícího formuláře nebo ovládacího prvku. Události jsou často definovány v rozhraní a v takovém případě musíte implementovat rozhraní pro implementaci události. Rozhraní System.ComponentModel.INotifyPropertyChanged definuje jednu System.ComponentModel.INotifyPropertyChanged.PropertyChanged událost. Následující kód ukazuje, jak implementovat událost, kterou toto zděděné rozhraní definovalo:

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)

Pokud chcete připojit událost v konstruktoru, je kód trochu složitější, protože připojení událostí musí být v then bloku v dalším konstruktoru, jak je znázorněno v následujícím příkladu:

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)

Viz také