2009-05-21 85 views
3

データグリッドビューを手動で更新するプログラムを作成しました。 - DGVを消去してデータを再挿入することによって、DGVを更新する方法があります。 - デザイナを使用して、DGVのCellEndEditのイベントハンドラを作成しました。イベントハンドラの内部では、データが更新され、& DGVのカスタムリフレッシュメソッドが呼び出されます。InvalidOperationException - セルの編集を終了し、別のセルに移動するとき

プログラムを実行している間、私は別のものを選択することで、細胞&終わり、それを編集を開始するたびに、例外がスローされます。それはSetCurrentCellAddressCore関数への再入可能呼び出しにつながるので 操作は有効ではありません

InvalidOperationExceptionがします。

Visual C#のデバッガは、データをクリアする行をマークします。datagridview1.Rows.Clear();

あなたは、問題を再現ビジュアルC#で新しいWindowsフォームプロジェクトを作成し、フォーム上のDataGridViewオブジェクトを入れ、Form1.csのために次のコードを貼り付けたい場合:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace Error___DataGridView_Updating___Cell_endedit 
{ 
    public partial class Form1 : Form 
    { 
     // Objects 
     DataTable dt; 
     DataColumn colID; 
     DataColumn colName; 
     DataColumn colInfo; 
     // Constructor 
     public Form1() 
     { 
      InitializeComponent(); 

      Initialize_dt(); 
      InsertSampleData_dt(); 
      Initialize_dataGridView1(); 
     } 

     // Methods 
     private void Initialize_dt() 
     { 
      dt = new DataTable(); 

      // Building Columns 
      // ID 
      colID = new DataColumn(); 
      colID.ColumnName = "ID"; 
      colID.DataType = typeof(int); 
      dt.Columns.Add(colID); 

      // Name 
      colName = new DataColumn(); 
      colName.ColumnName = "Name"; 
      colName.DataType = typeof(string); 
      dt.Columns.Add(colName); 

      //Info 
      colInfo = new DataColumn(); 
      colInfo.ColumnName = "Info"; 
      colInfo.DataType = typeof(string); 
      dt.Columns.Add(colInfo); 
     } 

     private void InsertSampleData_dt() 
     {    
      DataRow row; 

      // 0 
      row = dt.NewRow(); 
      row["ID"] = 100; 
      row["Name"] = "AAAA"; 
      row["Info"] = "First Record"; 
      dt.Rows.Add(row); 

      //1 
      row = dt.NewRow(); 
      row["ID"] = 101; 
      row["Name"] = "BBBB"; 
      row["Info"] = "Second Record"; 
      dt.Rows.Add(row); 


      //2 
      row = dt.NewRow(); 
      row["ID"] = 102; 
      row["Name"] = "CCCC"; 
      row["Info"] = "Third Record"; 
      dt.Rows.Add(row); 
     } 

     private void Initialize_dataGridView1() 
     { 
      dataGridView1.AllowUserToAddRows = false; 

      // Data Grid Definitions 
      //  Row Header 

      dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing; 
      dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders; 
      //  ColumnHeaders 
      dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells; 

      // Building Columns 
      #region ID 
      { 
       DataGridViewColumn colSGID = new DataGridViewTextBoxColumn(); 
       colSGID.Name = "ID"; 
       colSGID.HeaderText = "#"; 
       colSGID.ReadOnly = true; 
       colSGID.Visible = false; 
       colSGID.Resizable = DataGridViewTriState.False; 

       dataGridView1.Columns.Add(colSGID); 
      } 
      #endregion 

      #region Name 
      { 
       DataGridViewColumn colSGName = new DataGridViewTextBoxColumn(); 
       colSGName.Name = "Name"; 
       colSGName.HeaderText = "Name"; 

       dataGridView1.Columns.Add(colSGName); 
      } 
      #endregion 

      #region Info 
      { 
       DataGridViewColumn colSGSubject = new DataGridViewTextBoxColumn(); 
       colSGSubject.Name = "Info"; 
       colSGSubject.HeaderText = "Description"; 

       dataGridView1.Columns.Add(colSGSubject); 
      } 
      #endregion 

      Refresh_dataGridView1(); 
     } 

     private void Refresh_dataGridView1() 
     { 
      int index; 

      dataGridView1.SuspendLayout(); 

      dataGridView1.Rows.Clear(); 

      //MessageBox.Show("Cleared Data. Rebuilding..."); 

      foreach (DataRow row in dt.Rows) 
      { 
       index = dataGridView1.Rows.Add(new DataGridViewRow()); 

       dataGridView1.Rows[index].Cells["ID"].Value = row["ID"]; 
       dataGridView1.Rows[index].Cells["Name"].Value = row["Name"]; 
       dataGridView1.Rows[index].Cells["Info"].Value = row["Info"]; 

       //MessageBox.Show("row #" + index); 
      } 

      dataGridView1.ResumeLayout(); 
     } 

     //Event Handlers 
     private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) 
     { 
      bool toUpdate = false; 

      int id = (int)dataGridView1.Rows[e.RowIndex].Cells["ID"].Value; 
      string columnName = dataGridView1.Columns[e.ColumnIndex].Name; 
      string value = (string)dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value; 

      if (value == null) 
      { 
       value = string.Empty; 
      } 

      switch (columnName) 
      { 
       case "Name": 
        if (value == string.Empty) 
        { 
         MessageBox.Show("Name Can't Be Empty!"); 
        } 
        else 
        { 
         toUpdate = true; 
        } 
        break; 
       case "Info": 
        toUpdate = true; 
        break; 
      } 

      if (toUpdate) 
      { 
       foreach(DataRow row in dt.Rows) 
       { 
        if ((int)row["ID"] == id) 
        { 
         row[columnName] = value; 
        } 
       } 

       Refresh_dataGridView1(); 
      } 

     } 
    } 
} 
+0

忘れました。コードを貼り付けたら、次のようにプログラムを実行してください。 2)セルをクリックして(選択) 3)そのセルをもう一度クリックします(編集モードに入ります)。 4)別のセルを選択します(セルエンドの編集イベントが発生しましたが、例外がスローされるはずです)。 –

+0

私はあなたの問題を理解しましたが、達成しようとしていることを理解できません...もっと精巧にしてください。私が理解できる限り、あなたは細胞の価値を更新しようとしています...私は正しいのですか? –

+0

はい、データグリッドビュー*を使用してデータテーブルのセル値を更新しようとしています。私は手動でデータグリッドビューをバインドして、どのような値を許可するかどうかをより詳細に制御できるようにしました。 (*私の実際の「プロジェクト」では、テーブルアダプタを使用して型指定されたデータセットを更新しています) –

答えて

6

Bruce.ZhouさんのMSDNフォーラムでの回答があります。私はそれからスニペットをここに掲載しました。 Hereも元の投稿へのリンクです。

private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) 
{ 
    ...................................................; 
    if (toUpdate) 
    { 
     foreach(DataRow row in dt.Rows) 
     { 
      if ((int)row["ID"] == id) 
      { 
       row[columnName] = value; 
      } 
     } 

     this.BeginInvoke(new MethodInvoker(Refresh_dataGridView1)); 
    } 
} 

...

この修正を使用して、新しいセルが選択されるたびに、それ及び(含む)の最初のセルとの間のすべてのセルが選択されます。私は新しいセルだけを選択する方法を探しています。

1

私は、この問題を解決するために、最後の1時間、私の頭をキーボードに対してノックしました。 ここに私の回避策です: 問題を見て:別のセル(またはGridview内の任意のコントロール)を選択すると、EndEditがトリガーされます。

あなたの編集を適用する前に次のチェックを適用します。

public void myGrid_EndEdit(object sender, DataGridViewCellEventArgs e) 
{ 
    if (!myGrid.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected) 
       return; 
    //...rest of your code to apply edit below... 
} 

これは、編集中の任意のセルに適用する必要があります(フォーカスを失ったときので、編集が適用されません。タイピング入力編集を適用するために十分であろう)

0

私の回避策は、CellMouseDownイベントをキャプチャすることでした。アクションが編集中のセル以外であった場合は、DataGridView.EndEdit()を発行します。他のすべては期待どおりに動作します。

関連する問題