標籤:datagridview style blog tar ext c
資料繫結和資料網格視圖(DataGridView)控制項
資料網格視圖控制項,不像我們前面看到的控制項,它可以顯示多個列,但是,資料必須格式化,使資料網格知道要顯示哪一列。有兩種實現方法:一個是把資料網格視圖綁定到資料表(DataTable),另一個是把網格到綁定對象列表,對象有許多屬性,不同的屬性就成為網格的列。
下面的例子是一種簡單的解決方案,綁定到資料集(DataSet):
open System
open System.Collections.Generic
open System.Configuration
open System.Data
open System.Data.SqlClient
open System.Windows.Forms
// creates a connections then executes thegiven command on it
let createDataSet commandString =
//read the connection string
letconnectionSetting =
ConfigurationManager.ConnectionStrings.["MyConnection"]
//create a data adapter to fill the dataset
letadapter = new SqlDataAdapter(commandString, connectionSetting.ConnectionString)
//create a new data set and fill it
letds = new DataSet()
adapter.Fill(ds)|> ignore
ds
// create the data set that will be boundto the form
let dataSet = createDataSet "selecttop 10 * from Person.Contact"
// create a form containing a data bounddata grid view
let form =
lettemp = new Form()
letgrid = new DataGridView(Dock = DockStyle.Fill)
temp.Controls.Add(grid)
grid.DataSource<- dataSet.Tables.[0]
temp
// show the form
Application.Run(form)
運行前面的代碼,可以看到 9-2 顯示的結果。
圖 9-2 綁定了資料的資料網格
若不使用 DataSet,還可以使用 F# 記錄類型。這樣,通常需要建立一個泛型函數(generic
function),通過反射(reflection)建立並發布強型別集合。下面的代碼示範了這種泛型函數,把它封裝在模組中,這樣,就能更方便地把它用於其他代碼,然後,用這個模組執行對資料庫的查詢:
module Strangelights.DataTools
open System
open System.Collections.Generic
open System.Configuration
open System.Data
open System.Data.SqlClient
open Microsoft.FSharp.Reflection
// a command that returns dynamicallycreated stongly typed collection
let execCommand<‘a> commandString :seq<‘a> =
//the opener that executes the command
letopener() =
//read the connection string
letconnectionSetting =
ConfigurationManager.ConnectionStrings.["MyConnection"]
//create the connection and open it
letconn = new SqlConnection(connectionSetting.ConnectionString)
conn.Open()
//excute the command, ensuring the read will close the connection
letcmd = conn.CreateCommand(CommandType = CommandType.Text,
CommandText = commandString)
cmd.ExecuteReader(CommandBehavior.CloseConnection)
// the generator, that generates anstrongly typed object for each row
let generator (reader : IDataReader) =
ifreader.Read() then
//get the type object and its properties
lett = typeof<‘a>
//get the values for the row from the reader
letvalues = Array.create reader.FieldCount (new obj())
reader.GetValues(values)|> ignore
letconvertVals x = match box x with | :? DBNull -> null | _ -> x
letvalues = Array.map convertVals values
//create the record and return it
Some(FSharpValue.MakeRecord(t, values) :?> ‘a)
else
None
// generate the sequence
Seq.generate
opener
generator
(funr -> r.Dispose())
例子代碼的第一行使用了一個我們之前尚未用到過的方法,顯式聲明了函數的型別參數:
let execCommand<‘a> commandString :seq<‘a>
這樣做,能夠顯式給定泛型參數‘a,這個型別參數然後用於建立類型對象,再對它做反射:
let t = typeof<‘a>
這個函數是用來處理 F# 記錄類型,它的欄位完全符合查詢結果的欄位;如果不滿足這個先決條件,代碼就失敗;然而,這個先決條件通常是在應用程式中以反射的形式使用的。
前面已經定義的泛型函數 execCommand,能夠用於任何查詢,匹配記錄類型。下面的代碼示範如何應用:
open System
open System.Windows.Forms
open Strangelights.DataTools
// a type that mirrors the type of rowbeing created
type Contact =
{ContactID: Nullable<int>;
NameStyle:Nullable<bool>;
Title:string;
FirstName:string;
MiddleName:string;
LastName:string;
Suffix:string;
EmailAddress:string;
EmailPromotion:Nullable<int>;
Phone:string;
PasswordHash:string;
PasswordSalt:string;
AdditionalContactInfo:string;
rowguid:Nullable<Guid>;
ModifiedDate:Nullable<DateTime> }
// a form containing a data bound data grid
let form =
lettemp = new Form()
letgrid = new DataGridView(Dock = DockStyle.Fill)
temp.Controls.Add(grid)
letcontacts =
execCommand<Contact>"select top 10 * from Person.Contact"
letcontactsArray = contacts |> Seq.to_array
grid.DataSource<- contactsArray
temp
// show the form
Application.Run(form)
最重要的是下面一行:
let contacts =
execCommand<Contact>"select top 10 * from Person.Contact"
為泛型函數 execCommand 顯式聲明了型別參數。這個例子的結果同前面的例子, 9-2 所示。
注意
使用對象-關係映射,比例NHibernate,執行這種任務已經相當普遍,這些工具提供了高度的靈活性,但它們往往過度依賴於純正 C# 的功能,要想在 F# 中使用,體驗並不良好,因此,我在書中沒有討論任何相關內容。但是,許多人,包括我自己正在努力解決這個問題;同時,建議你關注我的部落格:http://strangelights.com/blog。