2012-07-27 156 views
1

我正在設計一個包含2個選項卡的TabControl的窗體窗體。我在每個選項卡中都有一個DataGridView,並且它們都填充了相同的列(包括DataGridViewCheckBoxColumn),但參數不同,因此最終用戶可以更輕鬆地使用它們,而不是全部包含在1個網格中。我可以在一個表單中使用多個DataGridViewRows嗎?

我想我可以爲每個DatagridView設置一個DataGridViewRow,並且它會在調用時將它們用作新實例,但似乎並非如此。

以下代碼在用戶選中或取消選中第一個選項卡的DataGridView中的複選框時正常工作;

private void dgvChq_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) 
    { 
     int column = e.ColumnIndex; 
     int row = e.RowIndex; 
     if (column == 5) 
     { 
      DataGridViewCheckBoxCell c = dgvChq[e.ColumnIndex, e.RowIndex] as DataGridViewCheckBoxCell; 
      if (c != null) 
      { 
       string a = e.FormattedValue.ToString(); 
       if (a == "True") 
       { 
        using (SqlCommand cmd = con.CreateCommand()) 
        { 
         cmd.CommandText = "UPDATE Customer.OrderHeader SET DateApproved = @approved WHERE OrderNumber = @ordNo"; 

         cmd.Parameters.AddWithValue("@approved", DateTime.Today); 
         cmd.Parameters.AddWithValue("@ordNo",dgvChq.Rows[row].Cells[0].Value.ToString()); 

         con.Open(); 
         cmd.ExecuteNonQuery(); 
         con.Close(); 
        } 
        DataGridViewRow dr = dgvChq.SelectedRows[0]; 
        dr.Cells[4].Value = DateTime.Today.ToString(); 
       } 
       else 
       { 
        using (SqlCommand cmd = con.CreateCommand()) 
        { 
         cmd.CommandText = "UPDATE Customer.OrderHeader SET DateApproved = NULL WHERE OrderNumber = @ordNo"; 

         cmd.Parameters.AddWithValue("@ordNo", dgvChq.Rows[row].Cells[0].Value.ToString()); 

         con.Open(); 
         cmd.ExecuteNonQuery(); 
         con.Close(); 
        } 
        DataGridViewRow dr = dgvChq.SelectedRows[0]; 
        dr.Cells[4].Value = ""; 
       } 
      } 
     } 
    } 

所以我想我可以使用不同的DataGridViewRow和重新使用此代碼在其他標籤中的其他的DataGridView,但它失敗;

private void dgvCredit_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) 
    { 
     int column = e.ColumnIndex; 
     int row = e.RowIndex; 
     if (column == 0) 
     { 
      DataGridViewCheckBoxCell c = dgvCredit[e.ColumnIndex, e.RowIndex] as DataGridViewCheckBoxCell; 
      if (c != null) 
      { 
       string a = e.FormattedValue.ToString(); 
       if (a == "True") 
       { 
        using (SqlCommand cmd = con.CreateCommand()) 
        { 
         cmd.CommandText = "UPDATE Customer.OrderHeader SET DateApproved = @approved WHERE OrderNumber = @ordNo"; 

         cmd.Parameters.AddWithValue("@approved", DateTime.Today); 
         cmd.Parameters.AddWithValue("@ordNo", dgvCredit.Rows[row].Cells[1].Value.ToString()); 

         con.Open(); 
         cmd.ExecuteNonQuery(); 
         con.Close(); 
        } 
        DataGridViewRow dgvr = dgvCredit.SelectedRows[0]; 
        dgvr.Cells[4].Value = DateTime.Today.ToString(); 
       } 
       else 
       { 
        using (SqlCommand cmd = con.CreateCommand()) 
        { 
         cmd.CommandText = "UPDATE Customer.OrderHeader SET DateApproved = NULL WHERE OrderNumber = @ordNo"; 

         cmd.Parameters.AddWithValue("@ordNo", dgvCredit.Rows[row].Cells[1].Value.ToString()); 

         con.Open(); 
         cmd.ExecuteNonQuery(); 
         con.Close(); 
        } 
        DataGridViewRow dgvr = dgvCredit.SelectedRows[0]; 
        dgvr.Cells[4].Value = ""; 
       } 
      } 
     } 
    } 

我錯過了這裏的東西,還是不可能在同一個表單中使用多個DataGridViewRows?

也許還有一種更「動態」的方式,我也可以這樣做,這可能有助於解決我的問題?

PS:它似乎是第二個datagridviewrow(dgvr)在單擊複選框時仍然顯示爲空,所以這是錯誤發生的位置。

+0

如果您複製並粘貼了數據網格,是否有機會讓它們具有相同的事件處理程序? – 2012-07-27 08:57:41

+0

你的代碼哭了一些重構和分離的業務邏輯:(:( – nawfal 2012-07-27 08:59:17

+0

而不是使用兩個數據網格,它是一個選項來簡單地過濾一個基於文本框的文本? – 2012-07-27 09:00:19

回答

1

@ Keefa2011,問題不在於DataGridViewRow實例。同意他們是引用類型,所以你在做這樣的實例成員變量時應該小心。但在您的代碼中,它們的範圍僅限於特定事件。

問題在於你提到的這一行。除非FullRowSelect已啓用,否則您總是會在DataGridViewRow dgvr = dgvCredit.SelectedRows[0];處得到異常。這是因爲選定的行數始終爲零。你需要處理。您可以通過啓用全行選擇或更改該錯誤行(如下所示)來完成。我不確定爲什麼只有第二個dgv出現錯誤。也許完整的行選擇爲第一個dgv啓用?

此外,您的代碼正在爲一些重構而哭泣。什麼你寫在兩頁是實際上只是這麼多:

private void dgvChq_CellValidating(object sender, 
            DataGridViewCellValidatingEventArgs e) 
{ 
    if (e.ColumnIndex != 5) 
     return; 

    HandleCheckedChanged(dgvChq, e, 
         Convert.ToInt32(dgvChq.Rows[e.RowIndex].Cells[0].Value)); 
} 

private void dgvCredit_CellValidating(object sender, 
             DataGridViewCellValidatingEventArgs e) 
{ 
    if (e.ColumnIndex != 0) 
     return; 

    HandleCheckedChanged(dgvCredit, e, 
         Convert.ToInt32(dgvCredit.Rows[e.RowIndex].Cells[1].Value)); 
} 

private void HandleCheckedChanged(DataGridView dgv, 
            DataGridViewCellValidatingEventArgs e, int id) 
{ 
    object toBeDisplayedDateValue = (bool)e.FormattedValue ? (DateTime?)DateTime.Today : null; 

    using (SqlCommand cmd = con.CreateCommand()) 
    { 
     cmd.CommandText = @"UPDATE Customer.OrderHeader 
          SET DateApproved = @approvedDate 
          WHERE OrderNumber = @ordNo"; 

     cmd.Parameters.AddWithValue("@approvedDate", toBeDisplayedDateValue); 
     cmd.Parameters.AddWithValue("@ordNo", id); 

     con.Open(); 
     cmd.ExecuteNonQuery(); 
     con.Close(); 
    } 

    dgv.Rows[e.RowIndex].Cells[4].Value = toBeDisplayedDateValue; //you could just do 
                    //this much 
    //or 

    //DataGridViewRow dgvr = dgv.SelectedRows[0]; //this line works only if there 
                //is at least one selected row when 
                //validating cell. For this you 
                //require 
                //dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect 
} 

你應該真正移動數據庫操作到另一個類有一個更清潔的設計。您的代碼最大的警告是您傳遞id爲"@ordNo"的地方。我只是把它移到了函數之外,因爲我不確定你是否應該從UI方面獲得這個值。該邏輯應該從數據庫端處理。換句話說,您應該將訂單號保存在其他地方,可能是dgv行的標籤左右。如果您確信gridview單元格中的值實際上可以用於數據庫中的正確記錄,那麼請繼續,您只需要傳遞order number列的列索引作爲參數。

另一件事,我不認爲你實際上需要單元格驗證事件,因爲每次將焦點移出單元格時它都會被觸發。由於其數據庫操作且價格昂貴,因此只有在單元格值發生更改時纔可以註冊cell value changed event。有一點需要注意的是,您應該在完全加載所有單元格後才能註冊該事件。否則,即使在最初填充記錄時也會被解僱。

例如,

private void Form1_Load(object sender, EventArgs e) 
{ 
    //--------------------------------------------- 
    // load dgv... 
    //--------------------------------------------- 

    dgvChq.CellValueChanged += dgvChq_CellValueChanged; 
    dgvCredit.CellValueChanged += dgvCredit_CellValueChanged; 
} 

private void dgvChq_CellValueChanged(object sender, DataGridViewCellEventArgs e) 
{ 
    if (e.ColumnIndex != 5) 
     return; 

    HandleCheckedChanged(dgvChq, e, 0); 
} 

private void dgvCredit_CellValueChanged(object sender, DataGridViewCellEventArgs e) 
{ 
    if (e.ColumnIndex != 0) 
     return; 

    HandleCheckedChanged(dgvCredit, e, 1); 
} 

private void HandleCheckedChanged(DataGridView dgv, DataGridViewCellEventArgs e, 
            int columnIndexOfOrderNo) 
{ 
    DataGridViewCheckBoxCell c = dgv[e.ColumnIndex, e.RowIndex] as DataGridViewCheckBoxCell; 
    object toBeDisplayedDateValue = (bool)c.EditedFormattedValue ? (DateTime?)DateTime.Today : null; 

    using (SqlCommand cmd = con.CreateCommand()) 
    { 
     cmd.CommandText = @"UPDATE Customer.OrderHeader 
          SET DateApproved = @approvedDate 
          WHERE OrderNumber = @ordNo"; 

     cmd.Parameters.AddWithValue("@approvedDate", toBeDisplayedDateValue); 
     cmd.Parameters.AddWithValue("@ordNo", 
            Convert.ToInt32(dgv.Rows[e.RowIndex].Cells[columnIndexOfOrderNo].Value)); 

     con.Open(); 
     cmd.ExecuteNonQuery(); 
     con.Close(); 
    } 

    dgv.Rows[e.RowIndex].Cells[4].Value = toBeDisplayedDateValue; 
} 

理論上,應該路過現場的columnIndex進行更新(在你的案件4)功能,因爲這些東西都可以在未來輕鬆dgvs不同。

+1

謝謝Nawfal,I已經使用了你的濃縮的重構代碼來解決我的問題,並且它很好地完成了這個技巧。我已經開始在週末玩Cell Value Changed事件了,但是無法得到你在這裏得到的結果,所以謝謝。爲此以及:) – keefa3011 2012-07-30 08:31:54

相關問題