2014年6月15日 星期日

DataGridView 控制項(1)

DataGridView 是一種表格樣式的控制項,專門用來顯示資料用的。 不論有沒有基礎資料來源,您都可以使用 DataGridView 控制項來顯示資料。 若沒有指定資料來源,你可以先建立包含資料的資料行和資料列,再將它們加入 DataGridView 。 若使用資料來源,你可以設定 DataSource 和 DataMember 屬性,讓 DataGridView 與資料建立繫結,就可以自動填入資料。

DataGridView 控制項架構

構成 DataGridView 控制項的相關類別,都包含在 System.Windows.Forms 命名空間中,而且全部都以 "DataGridView" 前置詞命名。 DataGridView 控制項是由兩個主要物件所組成:儲存格(Cells)和群組列(Bands),這些物件都是由 DataGridViewElement 類別衍生出來的。 下圖為 DataGridViewElement 類別的物件模型:

所以說,最主要用來與 DataGridView 控制項互動的類別,就是是底下三個:

儲存格

儲存格是最基本的互動單位,每一個儲存格都必須是一個 DataGridViewCell 型別,但是 DataGridViewCell 是一個抽象基底類別,所以實際的儲存格型別都是從它衍生出來的。

下列清單是 DataGridViewCell 的衍生類別:

  • DataGridViewButtonCell
  • DataGridViewTextBoxCell
  • DataGridViewCheckBoxCell
  • DataGridViewComboBoxCell
  • DataGridViewImageCell
  • DataGridViewLinkCell
  • DataGridViewHeaderCell
  • DataGridViewRowHeaderCell
  • DataGridViewColumnHeaderCell
  • DataGridViewTopLeftHeaderCell
  • 自訂型別的儲存格

儲存格樣式

你可以透過以下屬性來設定儲存格的樣式:

  • DefaultCellStyle
  • ColumnHeadersDefaultCellStyle
  • CellBorderStyle
  • GridColor
//若要讓資料列和資料行行首使用自訂的視覺化樣式
    //必須停止應用程式啟用的視覺化樣式.
    dgView2.EnableHeadersVisualStyles = false;

    //設定儲存格樣式,
    //只有在使用單一框線時,才可以將 GridColor 屬性設定為任何色彩;
    //若使用其他類型的框線,則是由作業系統指定色彩。
    dgView2.CellBorderStyle = DataGridViewCellBorderStyle.Single;
    dgView2.GridColor = Color.Blue ;   
            
    //定義一個樣式
    DataGridViewCellStyle headStyle = new DataGridViewCellStyle();
    headStyle.BackColor = Color.Yellow;
    headStyle.ForeColor = Color.Red;
    headStyle.Font = new Font("Verdana", 12, FontStyle.Bold);

    //定義一個樣式
    DataGridViewCellStyle cellStyle = new DataGridViewCellStyle();
    cellStyle.Font = new Font("Ariel", 12, FontStyle.Regular);

    //分配樣式給 ColumnHeader
    dgView2.ColumnHeadersDefaultCellStyle = headStyle;

    //分配樣式給 Columns
    dgView2.Columns.Add("col1", "col1_head");
    dgView2.Columns[0].DefaultCellStyle = cellStyle;

群組列

DataGridViewColumnDataGridViewRow 都算是一種群組列(Band)結構,二者都是衍生自 DataGridViewBand 基底類別。

資料行

DataGridViewColumn 類別是用來代表 DataGridView 控制項中的資料行,它主要是用來控制 Grid 的外觀和行為,也就是和 UI 相關的設定。 例如欄位寛度或儲存格的樣式等。

下圖為 DataGridViewColumn 類別的物件模型:

下面程式碼,簡單示範如何加入一個資料行到 DataGridView 控制項中

//定義一個資料行的樣式
    DataGridViewCellStyle cellStyle = new DataGridViewCellStyle();
    cellStyle.BackColor = Color.Aqua;
    cellStyle.Font = new Font("Verdana", 10, FontStyle.Bold);

    //定義一個用來放置TextBox型別的資料行
    DataGridViewCell Cell1 = new DataGridViewTextBoxCell();
    DataGridViewColumn Column1 = new DataGridViewColumn(Cell1);
    Column1.HeaderText = "Head1";
    Column1.Name = "Column1";

    //定義另一個用來放置ComboBox型別的資料行
    DataGridViewComboBoxCell Cell2 = new DataGridViewComboBoxCell();
    Cell2.Items.Add("111");
    Cell2.Items.Add("222");
    DataGridViewColumn Column2 = new DataGridViewColumn(Cell2);
    Column2.HeaderText = "Head2";
    Column2.Name = "Column2";

    //在 DataGridView 中加入資料行
    dgView2.Columns.Add(Column1);
    dgView2.Columns["Column1"].DefaultCellStyle = cellStyle;

    //在 DataGridView 中加入資料行
    dgView2.Columns.Add(Column2);

由上面例子可以知道,要用什麼型別的欄位,就必須在 DataGridViewColumn 中裝載什麼型別的 DataGridViewCell 。 在 .NET 中,已經事先定義好下列幾個常用的儲存格型別,它們都是 DataGridViewColumn 的衍生類別:

你就可以直接使用這些衍生類別來建立資料行。

//定義一個 DataGridViewTextBoxColumn
    DataGridViewTextBoxColumn Column3 = new DataGridViewTextBoxColumn();
    Column3.HeaderText = "Head3";
    Column3.Name = "Column3";
    dgView2.Columns.Add(Column3);

    //定義一個 DataGridViewCheckBoxColumn 
    DataGridViewCheckBoxColumn Column4 = new DataGridViewCheckBoxColumn();
    Column4.HeaderText = "Head4";
    Column4.Name = "Column4";
    dgView2.Columns.Add(Column4);

資料列

如果說 DataGridViewColumn 是用來設定 DataGridView 的欄位型態,那麼 DataGridViewRow 則是用來表示要顯示到 DataGridView 上的資料欄位。 您可以使用 Rows 集合,存取 DataGridView 控制項的資料列。 另外,可以使用 SelectedRows 集合,存取選取的資料列。

DataGridViewRow row = dgv.Rows[index];

    row.Cells[0].Value = trade.TradeNum;
    row.Cells[1].Value = trade.TradeDate;
    row.Cells[2].Value = trade.TradeType;
    row.Cells[3].Value = trade.StockID;
    row.Cells[4].Value = trade.StockName;

不使用繫結

若要使用 DataGridView 控制項來顯示資料,可分成三種模式:繫結、未繫結和虛擬。

未繫結模式適用於顯示少量的資料,由其對於靜態、唯讀的資料特別有用。 未繫結模式通常會藉由程式直接將資料填入控制項之中,

編輯資料行

如何加入資料行

構成 DataGridView 資料行的物件是 DataGridViewColumnCollection,它提供2個 Add 方法,可以用來加入資料行。

public virtual int Add(DataGridViewColumn dataGridViewColumn);
public virtual int Add(string columnName, string headerText);

若要建立一個 DataGridViewColumn , 必需提供一個 DataGridViewCell 當做參數。 不過由於 DataGridViewCell 是一個抽象類別, 所以直接提供一個 DataGridViewCell 的衍生類別:

DataGridViewCell 的衍生類別

DataGridViewColumn 的衍生類別

DataGridViewCell 相對應的, DataGridViewColumn 也有下列幾個衍生類別。

加入一個 DataGridViewColumn

DataGridViewCell cell = new DataGridViewTextBoxCell();          // 注意: DataGridViewCell 是個 virutal class
    DataGridViewColumn dgvCol = new DataGridViewColumn(cell);
    col1.HeaderText = "col1";
    col1.Name = "col1";
    dgv.Columns.Add(dgvCol);

加入一個 DataGridViewColumn 的衍生類別

// Add DataGridViewTextBoxColumn

    DataGridViewTextBoxColumn col2 = new DataGridViewTextBoxColumn();
    col2.HeaderText = "col2";
    col2.Name = "col2";
    dgv.Columns.Add(col2);

    // Add DataGridViewComboBoxColumn

    DataGridViewComboBoxColumn col4 = new DataGridViewComboBoxColumn();
    col4.Items.Add("item1");
    col4.Items.Add("item2");
    col4.Items.Add("item3");
    dgv.EditMode = DataGridViewEditMode.EditOnEnter;  //DataGridViewEditMode 預設值是 EditOnKeystrokeOrF2 ,改成 EditOnEnter 才不用點二次,即可進入編輯。
            
    col4.HeaderText = "col4";
    col4.Name = "col4";
    dgv.Columns.Add(col4);

直接加入資料行,並指定資料行行首文字

dgv.Columns.Add("col3", "col3_head");

資料行的屬性設定

資料行有多個屬性可以用來控制其外觀或表現行為,比較重要的有:

  • ReadOnly:是否唯讀。
  • Resizable:欄寛是否調整。
  • AutoSizeMode:寬度要以何種方式自動調整。
  • Frozen:設定某欄是否為凍結資料行。
DataGridViewColumn col2 = dgv.Columns[1];
    col2.Name = "col2";

    // 與[外觀]相關的屬性
    col2.HeaderText = "col2_head";
    col2.ToolTipText = "this is column 2";
    col2.Visible = true;

    // 設定 cell 樣式
    DataGridViewCellStyle style = new DataGridViewCellStyle();
    style.Font = new Font("細明體", 12);
    style.BackColor = Color.Yellow;
    col2.DefaultCellStyle = style;

    // 與[行為]相關的屬性
    col2.ReadOnly = false;
    col2.Resizable = DataGridViewTriState.True;
    col2.SortMode = DataGridViewColumnSortMode.Automatic;

    // 與[配置]相關的屬性
    dgv.Columns[2].Frozen = true;    // 設定凍結資料行
    dgv.Columns[0].Frozen = true;    // 因為Columns[2]為凍結資料行,2以前都算凍結
    col2.DividerWidth = 0;                // 設定資料行分割線的寬度(凍結欄與非凍結欄的間距).

    // 調整資料行寬度的方式
    col2.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;

    // 指定欄寛
    col2.Width = 200;            // 欄位寛度
    col2.MinimumWidth = 50;      // 欄位最小寛度
    col2.FillWeight = 200;       // 輸入盒寛度,必須大於 0
    //col.MaxInputLength = 5;     // 最大可輸入字元數

    dgv.Columns[3].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
    //dgv.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;  
    //凍結資料行不可以使用 Fill 屬性值

編輯資料列

如何加入資料列

構成 DataGridView 資料列的物件是 DataGridViewRowCollection,它提供4個 Add 方法,可以用來加入資料列。

public virtual int Add();
public virtual int Add(DataGridViewRow dataGridViewRow);
public virtual int Add(int count);
public virtual int Add(params object[] values);
//1. 加入一個空白列
    var index = dgv.Rows.Add();
    dgv.Rows[index].Cells["Column1"].Value = "Column1";
    dgv.Rows[index].Cells["Column1"].Value = "Column1";

    //2. 加入一個 DataGridViewRow
    DataGridViewRow row2 = (DataGridViewRow)dgv.Rows[0].Clone();
    row2.Cells[0].Value = "row2_c1";
    row2.Cells[1].Value = "row2_c2";
    row2.Cells[2].Value = "row2_c3";
    row2.Cells[3].Value = "item2";
    dgv.Rows.Add(row2);

    //3. 一次加入多列
    dgv.Rows.Add(2);

    //4. 加入一個指定內容的列
    string[] row = new string[] { "row3_c1", "row3_c2", "row3_c3", "item3"};
    dgv.Rows.Add(row);
    dgv.Rows.Add("row4_c1", "row4_c2", "row4_c3", "item4");

使用資料繫結

使用繫結方式,主要就是希望不要人工進行管理,希望 DataGridView 可以自動管理資料。 當 DataGridView 繫結資料時,控制項便會自動完成推入(pushed)和提取(pulled)資料列的操作。

DataGridView 控制項支援標準的 Windows Form 資料繫結模型,因此它可以繫結至下列清單中所描述的類別執行個體。

  • 實作 IList 介面的任何類別,例如一維陣列。
  • 實作 IListSource 介面的任何類別,例如 DataTable 和 DataSet 類別。
  • 實作 IBindingList 介面的任何類別,例如 BindingList<T> 類別。
  • 實作 IBindingListView 介面的任何類別,例如 BindingSource 類別。

顯示資料

DataGridViewAutoGenerateColumns 屬性為 true 時,在資料來源中的每個資料行都會自動在 DataGridView 控制項中產生對應的資料行。 如果偏好建立自己的資料行,您可以將 AutoGenerateColumns 屬性設定為 false,然後透過 DataPropertyName 屬性來繫結每個資料行。

private SqlDataAdapter objAdapter;

    private void GetData()
    {
        String strConn = ConfigurationManager.ConnectionStrings["EmpConnectionString"].ConnectionString;
        SqlConnection objConn = new SqlConnection(strConn);

        SqlCommand objCmd = new SqlCommand();
        objCmd.Connection = objConn;
        objCmd.CommandText = "SELECT ID, Name, Age FROM Emp";

        DataTable dt = new DataTable();
            
        objAdapter.SelectCommand = objCmd;
        objAdapter.Fill(dt);

        dataGridView1.DataSource = dt;
    }

加入資料

DataGridView 繫結到資料來源時,你就不允許對它的 DataGridViewRow 或 DataGridViewColumn 進行操作。 若要變更 DataGridView 上的內容,你可以重新繫結到新的資料來源,或者對原始的資料來源做調整。

tblPhoto photo = new tblPhoto();
photo.Title =  Path.GetFileNameWithoutExtension(file.FullName);
photo.Summary = photo.Title;
photo.FileName = file.FullName;
photo.MD5 = md5;
photo.SyncState = SyncStateEnum.New;

bsDetail.Add(photo);  //在 bind source 中加入一筆新的資料。

更新資料庫

要將資料更新回資料庫,可以直接叫用 DataAdapter 的 Update 方法,不過在叫用 Update 方法。 同樣的,在叫用前當然給先給定一個 UpdateCommand 物件,不過,如果要更改的對向是單一資料表,可以直接簡單的指定一個 SqlCommandBuilder 物件, SqlCommandBuilder 物件,它就會依據 SelectCommand 內容,自動產生更新命令,這樣叫用 Update 方法才會有效。 否則會產生錯誤訊息:「當傳遞擁有已修改資料列的 DataRow 集合時,更新需要有效的 UpdateCommand」。

private void btnUpdate_Click(object sender, EventArgs e)
    {
        //使用 CommandBuilder 來產生相對應的 Insert, Delete, Update SQL語法
        var cmdBuilder = new SqlCommandBuilder();
        cmdBuilder.DataAdapter = objAdapter;  
        objAdapter.Update(((DataTable)dataGridView1.DataSource));
    }

2 則留言:

  1. 作者已經移除這則留言。

    回覆刪除
  2. 請問 DataGridViewComboBoxColumn 資料透過 DataSource傳入 並新增至DataGridView上
    可以指定Combobox的初值嗎? 謝謝

    回覆刪除