function to Visualizing Data in a Grid in F#
I wrote the following function to view data in a grid from F# interactive:
open System.Windows.Forms
let grid x =
let form = new Form(Visible = true)
let data = new DataGridView(Dock = DockStyle.Fill)
form.Controls.Add(data)
data.DataSource <- x |> Seq.toArray
How can I make it work开发者_JAVA技巧 for both 1D and 2D seqs? say, grid [1,2,3]
or grid[(1,0);(2,0);(3,0)];;
works fine but grid [1;2;3];;
would not work.
another question is, why do I have to add the `|>Seq.toArray to make it work?
DataGridView uses databinding that reflects over object properties and displays them in grid columns (possibly automatically inferred). [1,2,3] and [(1,0);(2,0);(3,0)] are lists of tuples so DataGridView can show tuple components, As opposite, [1;2;3] - list of integers, it doesn't contains any properties that exposes the actual value.
Seq.ToArray is necessary because DataSource expects IList, IListSource, IBindingList or IBindingListView (DataGridView.DataSource Property ). Array implements IList, F# list - doesn't.
As desco explains, the DataGridView
control displays values of properties of the object.
This is pretty silly behavior for primitive types - for example if you specify [ "Hello"; "world!" ]
as the data source, it will display column Length
with values 5 and 6. That's definitely not what you'd want!
The best solution I could find is to explicitly check for strings and primitive types and wrap them in a simple type with just a single property (that will get displayed):
type Wrapper(s:obj) =
member x.Value = s.ToString()
let grid<'T> (x:seq<'T>) =
let form = new Form(Visible = true)
let data = new DataGridView(Dock = DockStyle.Fill)
form.Controls.Add(data)
data.AutoGenerateColumns <- true
if typeof<'T>.IsPrimitive || typeof<'T> = typeof<string> then
data.DataSource <- [| for v in x -> Wrapper(box v) |]
else
data.DataSource <- x |> Seq.toArray
grid [ 1 .. 10 ]
grid [ "Hello"; "World" ]
精彩评论