Tuesday, December 20, 2011

Use F# to Implement INotifiyCollectionChanged Interface

Today I find the INotifyCollectionChange interface on C# portable library. Because it is the core part of data binding to collection, I decide to implement this interface.

This implementation covers the following concepts, please also scroll down to see the full list.. :-)

  • declare an F# type (see color)
  • declare event (see color)
  • constructor: invoke base method (see color)
  • implement interface (see color)
  • mutable variable (see highlight comment)
  • inheritance (see highlight comment)
The other features are list at end of the page.



type ObservableList < 'T > () = 
    inherit List<'T>()     //inherit List
        
    let collectionChanged = Event< _ , _ > ( )


    let mutable isTriggerEvent = false   //mutable varaible


    new(items) = ObservableList<'T>() then base.AddRange(items)


    interface INotifyCollectionChanged with
        [ <  CLIEvent  > ]
        member this.CollectionChanged = collectionChanged.Publish


    member this.IsTriggerEvent
        with get() = isTriggerEvent
        and set(v) = isTriggerEvent <- v


    member this.Add(n:'T) = 
        base.Add(n)
        this.TriggerAdd(n, base.Count)


    member this.Remove(n:'T) = 
        let index = this.IndexOf(n)
        if index <> -1 then
            let r = base.Remove(n)
            this.TriggerRemove(n, index)
            r
        else 
            false


    member this.Remove(n:'T seq) =
        n |> Seq.iter (this.Remove >> ignore)
    member this.RemoveAt(index) = 
        if this.Count > 0 then 
            if index >=0 && index < this.Count then
                let item = base.[index]
                base.RemoveAt(index)
                this.TriggerRemove(item, index)
    member this.RemoveRange(index, count) = 
        [0..count-1] |> Seq.iter (fun i -> this.RemoveAt(index))


    member this.Sort()= 
        base.Sort()
        this.TriggerReset()
    member this.Sort(comparer) = 
        base.Sort(comparer)
        this.TriggerReset()
    member this.Sort(index, count, comparer) = 
        base.Sort(index, count, comparer)
        this.TriggerReset()


    member this.Reverse() = 
        base.Reverse()
        this.TriggerReset()
    member this.Reverse(index, count) = 
        base.Reverse(index, count)
        this.TriggerReset()


    member this.AddRange(items) = 
        items |> Seq.iter this.Add


    member this.Clear() = 
        base.Clear()
        this.TriggerReset()


    member this.Insert(index, item) = 
        base.Insert(index, item)
        this.TriggerAdd(item, index)
    member this.InsertRange(index, items) = 
       items |> Seq.iteri (fun i item -> this.Insert(index+i, item))


    member this.Item
        with get(i) = base.[i]
        and set i v = 
            let old = base.[i]
            base.[i] <- v
            this.TriggerReplace(v, old, i)


    member private this.TriggerAdd(item, index) =
        if this.IsTriggerEvent then
            collectionChanged.Trigger(this, NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index))
    member private this.TriggerRemove(item, index) =
        if this.IsTriggerEvent then
            collectionChanged.Trigger(this, NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index))
    member private this.TriggerReplace(item, oldItem, index) =
        if this.IsTriggerEvent then
            collectionChanged.Trigger(this, NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem, index))
    member public this.TriggerReset() =
        if this.IsTriggerEvent then
            collectionChanged.Trigger(this, NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, null, -1))


    static member FromList(items) = ObservableList(items)


(continue)
  • indexed property (see color)
  • trigger event (see color)
  • static method (see color)
  • public and private member (see color)


No comments: