我可以在一个表单中使用多个DataGridViewRows吗?

问题描述:

我正在设计一个包含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

@ 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