2 people like it.

SortableBindingList

SortableBindingList suitable for use with WinForms DataGridView.

 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: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
open System
open System.Collections.Generic
open System.ComponentModel

// SortableBindingList in F# adapted from msmolcic on Stack Overflow
// https://stackoverflow.com/questions/23661195/datagridview-using-sortablebindinglist

type SortableBindingList<'T>(list:IEnumerable<'T>) =
    inherit BindingList<'T>(List(list))

    let mutable isSorted = false
    let mutable sortDirection = ListSortDirection.Ascending
    let mutable sortProperty : PropertyDescriptor option = None

    new () = SortableBindingList(Seq.empty<'T>)

    override l.ApplySortCore(prop, direction) =
        let raiseEx () =
            new NotSupportedException("Cannot sort by " + prop.Name +
                ". This" + prop.PropertyType.ToString() + " does not implement IComparable")
            |> raise

        match prop.PropertyType.GetInterface("IComparable") with
        | null ->
            if prop.PropertyType.IsValueType then
                match Nullable.GetUnderlyingType(prop.PropertyType) with
                | null -> raiseEx()
                | t -> 
                    match t.GetInterface("IComparable") with 
                    | null -> raiseEx() 
                    | _ -> () // Just fall through the match case and apply the sort
        | _ -> () // Just fall through the match case and apply the sort
        
        // IComparable interface is supported, so apply the sort
        let query = base.Items :> IEnumerable<'T>
        sortProperty <- Some prop
        sortDirection <- direction

        let sorted =
            match direction with
            | ListSortDirection.Ascending ->
                query |> Seq.sortBy (fun i -> prop.GetValue(i) :?> IComparable)
            | _ ->
                query |> Seq.sortByDescending (fun i -> prop.GetValue(i) :?> IComparable)
            |> Array.ofSeq
        
        // Can't access protected "Items" within lambda, so use this for loop construct
        for i in [0 .. Array.length sorted - 1] do
            l.Items.[i] <- sorted.[i] 
        isSorted <- true
        l.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1))

    override __.SortPropertyCore =
        match sortProperty with
        | Some sp -> sp
        | _ ->
             new System.NullReferenceException("Sortable property was null.")
             |> raise

    override __.SortDirectionCore = sortDirection
    override __.SupportsSortingCore = true
    override __.IsSortedCore = isSorted
namespace System
namespace System.Collections
namespace System.Collections.Generic
namespace System.ComponentModel
Multiple items
type SortableBindingList<'T> =
  inherit BindingList<'T>
  new : unit -> SortableBindingList<'T>
  new : list:IEnumerable<'T> -> SortableBindingList<'T>
  override ApplySortCore : prop:PropertyDescriptor * direction:ListSortDirection -> unit
  override IsSortedCore : bool
  override SortDirectionCore : ListSortDirection
  override SortPropertyCore : PropertyDescriptor
  override SupportsSortingCore : bool

Full name: Script.SortableBindingList<_>

--------------------
new : unit -> SortableBindingList<'T>
new : list:IEnumerable<'T> -> SortableBindingList<'T>
Multiple items
val list : IEnumerable<'T>

--------------------
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
type IEnumerable<'T> =
  member GetEnumerator : unit -> IEnumerator<'T>

Full name: System.Collections.Generic.IEnumerable<_>
Multiple items
type BindingList<'T> =
  inherit Collection<'T>
  new : unit -> BindingList<'T> + 1 overload
  member AddNew : unit -> 'T
  member AllowEdit : bool with get, set
  member AllowNew : bool with get, set
  member AllowRemove : bool with get, set
  member CancelNew : itemIndex:int -> unit
  member EndNew : itemIndex:int -> unit
  member RaiseListChangedEvents : bool with get, set
  member ResetBindings : unit -> unit
  member ResetItem : position:int -> unit
  ...

Full name: System.ComponentModel.BindingList<_>

--------------------
BindingList() : unit
BindingList(list: IList<'T>) : unit
Multiple items
type List<'T> =
  new : unit -> List<'T> + 2 overloads
  member Add : item:'T -> unit
  member AddRange : collection:IEnumerable<'T> -> unit
  member AsReadOnly : unit -> ReadOnlyCollection<'T>
  member BinarySearch : item:'T -> int + 2 overloads
  member Capacity : int with get, set
  member Clear : unit -> unit
  member Contains : item:'T -> bool
  member ConvertAll<'TOutput> : converter:Converter<'T, 'TOutput> -> List<'TOutput>
  member CopyTo : array:'T[] -> unit + 2 overloads
  ...
  nested type Enumerator

Full name: System.Collections.Generic.List<_>

--------------------
List() : unit
List(capacity: int) : unit
List(collection: IEnumerable<'T>) : unit
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val mutable isSorted : bool
val mutable sortDirection : ListSortDirection
type ListSortDirection =
  | Ascending = 0
  | Descending = 1

Full name: System.ComponentModel.ListSortDirection
field ListSortDirection.Ascending = 0
val mutable sortProperty : PropertyDescriptor option
type PropertyDescriptor =
  inherit MemberDescriptor
  member AddValueChanged : component:obj * handler:EventHandler -> unit
  member CanResetValue : component:obj -> bool
  member ComponentType : Type
  member Converter : TypeConverter
  member Equals : obj:obj -> bool
  member GetChildProperties : unit -> PropertyDescriptorCollection + 3 overloads
  member GetEditor : editorBaseType:Type -> obj
  member GetHashCode : unit -> int
  member GetValue : component:obj -> obj
  member IsLocalizable : bool
  ...

Full name: System.ComponentModel.PropertyDescriptor
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
union case Option.None: Option<'T>
module Seq

from Microsoft.FSharp.Collections
val empty<'T> : seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.empty
val l : SortableBindingList<'T>
override SortableBindingList.ApplySortCore : prop:PropertyDescriptor * direction:ListSortDirection -> unit

Full name: Script.SortableBindingList`1.ApplySortCore
val prop : PropertyDescriptor
val direction : ListSortDirection
val raiseEx : (unit -> 'a)
Multiple items
type NotSupportedException =
  inherit SystemException
  new : unit -> NotSupportedException + 2 overloads

Full name: System.NotSupportedException

--------------------
NotSupportedException() : unit
NotSupportedException(message: string) : unit
NotSupportedException(message: string, innerException: exn) : unit
property MemberDescriptor.Name: string
property PropertyDescriptor.PropertyType: Type
Type.ToString() : string
val raise : exn:Exception -> 'T

Full name: Microsoft.FSharp.Core.Operators.raise
Type.GetInterface(name: string) : Type
Type.GetInterface(name: string, ignoreCase: bool) : Type
property Type.IsValueType: bool
Multiple items
type Nullable =
  static member Compare<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> int
  static member Equals<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> bool
  static member GetUnderlyingType : nullableType:Type -> Type

Full name: System.Nullable

--------------------
type Nullable<'T (requires default constructor and value type and 'T :> ValueType)> =
  struct
    new : value:'T -> Nullable<'T>
    member Equals : other:obj -> bool
    member GetHashCode : unit -> int
    member GetValueOrDefault : unit -> 'T + 1 overload
    member HasValue : bool
    member ToString : unit -> string
    member Value : 'T
  end

Full name: System.Nullable<_>

--------------------
Nullable()
Nullable(value: 'T) : unit
Nullable.GetUnderlyingType(nullableType: Type) : Type
val t : Type
val query : IEnumerable<'T>
union case Option.Some: Value: 'T -> Option<'T>
val sorted : 'T []
val sortBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Seq.sortBy
val i : 'T
PropertyDescriptor.GetValue(component: obj) : obj
Multiple items
type IComparable =
  member CompareTo : obj:obj -> int

Full name: System.IComparable

--------------------
type IComparable<'T> =
  member CompareTo : other:'T -> int

Full name: System.IComparable<_>
val sortByDescending : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Seq.sortByDescending
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val ofSeq : source:seq<'T> -> 'T []

Full name: Microsoft.FSharp.Collections.Array.ofSeq
val i : int
val length : array:'T [] -> int

Full name: Microsoft.FSharp.Collections.Array.length
property Collections.ObjectModel.Collection.Items: IList<'T>
BindingList.OnListChanged(e: ListChangedEventArgs) : unit
Multiple items
type ListChangedEventArgs =
  inherit EventArgs
  new : listChangedType:ListChangedType * newIndex:int -> ListChangedEventArgs + 3 overloads
  member ListChangedType : ListChangedType
  member NewIndex : int
  member OldIndex : int
  member PropertyDescriptor : PropertyDescriptor

Full name: System.ComponentModel.ListChangedEventArgs

--------------------
ListChangedEventArgs(listChangedType: ListChangedType, newIndex: int) : unit
ListChangedEventArgs(listChangedType: ListChangedType, propDesc: PropertyDescriptor) : unit
ListChangedEventArgs(listChangedType: ListChangedType, newIndex: int, propDesc: PropertyDescriptor) : unit
ListChangedEventArgs(listChangedType: ListChangedType, newIndex: int, oldIndex: int) : unit
type ListChangedType =
  | Reset = 0
  | ItemAdded = 1
  | ItemDeleted = 2
  | ItemMoved = 3
  | ItemChanged = 4
  | PropertyDescriptorAdded = 5
  | PropertyDescriptorDeleted = 6
  | PropertyDescriptorChanged = 7

Full name: System.ComponentModel.ListChangedType
field ListChangedType.Reset = 0
override SortableBindingList.SortPropertyCore : PropertyDescriptor

Full name: Script.SortableBindingList`1.SortPropertyCore
val sp : PropertyDescriptor
Multiple items
type NullReferenceException =
  inherit SystemException
  new : unit -> NullReferenceException + 2 overloads

Full name: System.NullReferenceException

--------------------
NullReferenceException() : unit
NullReferenceException(message: string) : unit
NullReferenceException(message: string, innerException: exn) : unit
val __ : SortableBindingList<'T>
override SortableBindingList.SortDirectionCore : ListSortDirection

Full name: Script.SortableBindingList`1.SortDirectionCore
override SortableBindingList.SupportsSortingCore : bool

Full name: Script.SortableBindingList`1.SupportsSortingCore
override SortableBindingList.IsSortedCore : bool

Full name: Script.SortableBindingList`1.IsSortedCore
Raw view Test code New version

More information

Link:http://fssnip.net/7Tk
Posted:6 years ago
Author:Mike Weiss
Tags: winforms