3 people like it.

Map for ObservableCollection

The snippet implements 'map' and 'init' functions for the 'ObservableCollection' type. These are similar to well-known functions for sequences, but 'map' works in an incremental fashion. When the source collection changes, the resulting collection is updated.

Implementation

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
    open System.Collections.Specialized
    open System.Collections.ObjectModel
    
    module ObservableCollection =
      /// Initialize observable collection
      let init n f = ObservableCollection<_>(List.init n f)

      /// Incremental map for observable collections
      let map f (oc:ObservableCollection<'T>) =
        // Create a resulting collection based on current elements
        let res = ObservableCollection<_>(Seq.map f oc)
        // Watch for changes in the source collection
        oc.CollectionChanged.Add(fun change ->
          printfn "%A" change.Action
          match change.Action with
          | NotifyCollectionChangedAction.Add ->
              // Apply 'f' to all new elements and add them to the result
              change.NewItems |> Seq.cast<'T> |> Seq.iteri (fun index item ->
                res.Insert(change.NewStartingIndex + index, f item))
          | NotifyCollectionChangedAction.Move ->
              // Move element in the resulting collection
              res.Move(change.OldStartingIndex, change.NewStartingIndex)
          | NotifyCollectionChangedAction.Remove ->
              // Remove element in the result
              res.RemoveAt(change.OldStartingIndex)
          | NotifyCollectionChangedAction.Replace -> 
              // Replace element with a new one (processed using 'f')
              change.NewItems |> Seq.cast<'T> |> Seq.iteri (fun index item ->
                res.[change.NewStartingIndex + index] <- f item)
          | NotifyCollectionChangedAction.Reset ->
              // Clear everything
              res.Clear()
          | _ -> failwith "Unexpected action!" )
        res

Sample usage

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
    // Create source collection and result using 'map'
    let src = ObservableCollection.init 5 (fun n -> n)
    let res = ObservableCollection.map (fun x -> 
      printfn "processing %d" x; x * 10) src
    
    // Manipulate elements in the source
    src.Move(0, 1)
    src.Remove(0)
    src.Clear()
    src.Add(5)
    src.Insert(0, 3)
    src.[0] <- 1
    
    // Compare the original and the result
    printfn "%A" (Seq.zip src res |> List.ofSeq)
namespace System
namespace System.Collections
namespace System.Collections.Specialized
namespace System.Collections.ObjectModel
Multiple items
type ObservableCollection<'T> =
  inherit Collection<'T>
  new : unit -> ObservableCollection<'T> + 2 overloads
  member Move : oldIndex:int * newIndex:int -> unit
  event CollectionChanged : NotifyCollectionChangedEventHandler

Full name: System.Collections.ObjectModel.ObservableCollection<_>

--------------------
ObservableCollection() : unit
ObservableCollection(list: System.Collections.Generic.List<'T>) : unit
ObservableCollection(collection: System.Collections.Generic.IEnumerable<'T>) : unit
val init : n:int -> f:(int -> 'a) -> ObservableCollection<'a>

Full name: Script.ObservableCollection.init


 Initialize observable collection
val n : int
val f : (int -> 'a)
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val init : length:int -> initializer:(int -> 'T) -> 'T list

Full name: Microsoft.FSharp.Collections.List.init
val map : f:('T -> 'a) -> oc:ObservableCollection<'T> -> ObservableCollection<'a>

Full name: Script.ObservableCollection.map


 Incremental map for observable collections
val f : ('T -> 'a)
val oc : ObservableCollection<'T>
val res : ObservableCollection<'a>
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
event ObservableCollection.CollectionChanged: IEvent<NotifyCollectionChangedEventHandler,NotifyCollectionChangedEventArgs>
member System.IObservable.Add : callback:('T -> unit) -> unit
val change : NotifyCollectionChangedEventArgs
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
property NotifyCollectionChangedEventArgs.Action: NotifyCollectionChangedAction
type NotifyCollectionChangedAction =
  | Add = 0
  | Remove = 1
  | Replace = 2
  | Move = 3
  | Reset = 4

Full name: System.Collections.Specialized.NotifyCollectionChangedAction
field NotifyCollectionChangedAction.Add = 0
property NotifyCollectionChangedEventArgs.NewItems: System.Collections.IList
val cast : source:System.Collections.IEnumerable -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.cast
val iteri : action:(int -> 'T -> unit) -> source:seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iteri
val index : int
val item : 'T
Collection.Insert(index: int, item: 'a) : unit
property NotifyCollectionChangedEventArgs.NewStartingIndex: int
field NotifyCollectionChangedAction.Move = 3
ObservableCollection.Move(oldIndex: int, newIndex: int) : unit
property NotifyCollectionChangedEventArgs.OldStartingIndex: int
field NotifyCollectionChangedAction.Remove = 1
Collection.RemoveAt(index: int) : unit
field NotifyCollectionChangedAction.Replace = 2
field NotifyCollectionChangedAction.Reset = 4
Collection.Clear() : unit
val failwith : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.failwith
val src : ObservableCollection<int>

Full name: Script.src
val res : ObservableCollection<int>

Full name: Script.res
val x : int
Collection.Remove(item: int) : bool
Collection.Add(item: int) : unit
Collection.Insert(index: int, item: int) : unit
val zip : source1:seq<'T1> -> source2:seq<'T2> -> seq<'T1 * 'T2>

Full name: Microsoft.FSharp.Collections.Seq.zip
val ofSeq : source:seq<'T> -> 'T list

Full name: Microsoft.FSharp.Collections.List.ofSeq
Raw view Test code New version

More information

Link:http://fssnip.net/dv
Posted:11 years ago
Author:Tomas Petricek
Tags: observablecollection , reactive , linq , sequences