My Technical Notes

Monday, 11 August 2014

F#: Showing Data in a Grid


//#region DataTableUtils

open System
open System.Data

module DataTableUtil =
    let toDataTable rows =
        let rows = rows |> Seq.cast<DataRow> |> Seq.toList
        match rows with
        | [] -> new DataTable()
        | x::xs -> 
            let dt = x.Table.Clone()
            for row in rows do
                dt.Rows.Add(row.ItemArray) |> ignore
            dt

//#endregion DataTableUtils

//#region Seq.tryHead definition

module Seq =
    let tryHead xs = xs |> Seq.tryPick Some

//#endregion Seq.tryHead definition

//#region As definition

let (|As|_|) (p:'T) : 'U option =
    let p = p :> obj
    if p :? 'U then Some (p :?> 'U) else None

//#endregion As definition

//#region grid code

open System.Drawing
open System.Windows.Forms
open System.Data
open System.Collections
open System.Collections.Generic

let showGrid data =
    let form = new Form(Visible = true, Text = "A Simple F# Form",
                        TopMost = true, Size = Size(600,600))

    let gv = new DataGridView(Dock = DockStyle.Fill, Text = "F# Programming is Fun!")
    form.Controls.Add(gv)
    let dataSource =
        match data with
        | As (dt:DataTable) -> dt :> obj
        | As (xs:IEnumerable) -> 
            let first = xs |> Seq.cast<obj> |> Seq.tryHead
            match first with
            | None -> data
            | Some first -> 
                match first with
                | As (dr:DataRow) -> 
                    (DataTableUtil.toDataTable xs) :> obj
                | _ -> Generic.List<obj>(xs |> Seq.cast<obj>) :> obj
        | _ -> data
    gv.DataSource <- dataSource

//#endregion grid code

Note that if you pass in a List or a Seq, then it won't work, instead pass in an Array.

No comments: