Implementing INotifyPropertyChanged with F#

I like F# for a lot of things, but, man, is it a pain to support events. In C# it’s trivial to implement an interface like INotifyPropertyChanged consisting only of an event, but in F# you have to jump through some hoops to map native functions to delegates/events. F# is generally much terser than C# and other .NET languages, but not in this case. After spending some time the other day trying to figure out the right combination of syntax and helper functions (and unsucessfully googling for it), I thought I’d upload a bare-bones implementation here as an aide-memoire.

open System.ComponentModel
 
type MyObject() =
    let mutable propval = 0.0
 
    let event = Event<_, _>()
 
    interface INotifyPropertyChanged with
        member this.add_PropertyChanged(e) =
            event.Publish.AddHandler(e)
        member this.remove_PropertyChanged(e) =
            event.Publish.RemoveHandler(e)
 
    member this.MyProperty
        with get() = propval
        and  set(v) =
            propval <- v
            event.Trigger(this, new PropertyChangedEventArgs("MyProperty"))

It turns out that in F# version 1.9.6.16 there’s a slightly more concise syntax for this, as pointed out by Rei in the comments (thanks!). It uses the CLIEvent attribute to hook up the .NET event:

open System.ComponentModel
 
type MyObject() =
    let mutable propval = 0.0
 
    let propertyChanged = Event<_, _>()
    interface INotifyPropertyChanged with
        [<clievent>]
        member x.PropertyChanged = propertyChanged.Publish
 
    member this.MyProperty
        with get() = propval
        and  set(v) =
            propval <- v
            propertyChanged.Trigger(this, new PropertyChangedEventArgs("MyProperty"))
This entry was posted in F# and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

4 Comments

  1. csappenf
    Posted March 24, 2009 at 1:37 pm | Permalink

    Thanks. I was looking at this problem last night, and didn’t find much documentation to guide me.

  2. rei
    Posted July 6, 2009 at 5:37 am | Permalink

    Here’s a much easier way to do it:

    let propertyChanged = Event()
    interface INotifyPropertyChanged with
    []
    member x.PropertyChanged = propertyChanged.Publish

    member private x.propchg p = propertyChanged.Trigger(x, PropertyChangedEventArgs(p))

  3. rei
    Posted July 6, 2009 at 5:38 am | Permalink

    Blah, lost the brackets to html. Let’s try again:


    let propertyChanged = Event<_, _>()
    interface INotifyPropertyChanged with
    [<CLIEvent>]
    member x.PropertyChanged = propertyChanged.Publish

    member private x.propchg p = propertyChanged.Trigger(x, PropertyChangedEventArgs(p))

  4. Posted July 6, 2009 at 9:41 am | Permalink

    Thanks Rei! I’ve updated the post to mention the new attribute (and change the code to use type inference for the event type).

    Ian

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">