DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DataGridのデータ更新について

環境/言語:[OS : Windows 2000 Professional / 言語 : C# / .NET Framework : 1.1]
分類:[.NET]

【解決したい問題】

初めまして、初投稿となるirvと申します。
DataGridにあるデータの更新についてお聞きしたい事があります。

フォームにDataGridを配置して
そこへ格納している文字データをforループで
どんどん追加していく、というプログラムを作成しています。

そして、DataGrid内に入力されたデータが範囲外のデータだったら
DataGridを一度クリアして、格納している以前のデータを再設定、
という処理を行おうとして
-----------------------------------------------------------------
  // グリッド内のデータをクリア
  DataSet->Clear();

  // データを再設定
  for ( int index = 0; index < (文字データ配列の数); ++index )
  {
    …
    DataTable->Rows->Add(追加データ)
  }
-----------------------------------------------------------------
というDataGridの更新(再設定)を行う関数を呼び出す処理を
「ColumnChanged」イベントの内部に追加しました。

しかし、DataGridの更新を行った後に先頭(Row0番目のデータ)
以外の部分のデータを更新してEnterキーを押したりすると、
入力フォーカスが離れた「Leave」のイベントが発生してしまい、
カラムの値を変更した「ColumnChanged」イベントが発生してくれません。

が、何故か先頭のデータを更新すると「Leave」イベントが起こらずに
ちゃんと「ColumnChanged」イベントが発生し、
その後はRow1番目以降のデータでも「ColumnChanged」イベント
が発生するようになります。

これはDataGridデータの更新方法に問題があるのでしょうか?
ご教授、宜しくお願い致します。

【解決するために何をしたか】

フォーカスがDataGridにある事が問題かと思い
強制的に他へフォーカスを移したりしましたが、
変化がありませんでした。
2005/10/19(Wed) 15:32:54 編集(投稿者)

お世話になります。

■No13326に返信(irvさんの記事)
まず、Windowsアプリケーションでしょうか?
# ColumnChangedイベントがちょっと見つけられなかったのですが…

また、やりたい事は、以下の事で宜しいでしょうか?
1) DataTableにデータをForループで追加する。
 ↓
2) 1)で作成したDataTableをDataGridにバインドする。
 ↓
3) ユーザーがDataGridに入力し、
  入力された値がエラー(範囲外)のデータであった場合、
  1)で表示したデータに戻したい。
===============================================================
↑の事がやりたいのであれば、非効率ですが
こんな感じではいかがでしょうか。
(VBで書いたコードをテキストエディタでC#に書き直したので
 間違ってるかもしれません(汗
===============================================================
■メンバ変数
private DataTable m_orgDt;

■画面ロード時
DataTable dt = new DataTable();
dt.Columns.Add("test");

this.m_orgDt = dt.Clone();
for ( int i=0; i<=1000 ; i++) {
  DataRow row = dt.NewRow();
  row["test"] = i;
  dt.Rows.Add(row);

  // OriginalValueをとっておく
  this.m_orgDt.ImportRow(row);
}
this.dataGrid1.DataSource = dt;
this.dataGrid1.Refresh();

■dataGrid1.CurrentCellChanged と dataGrid1.Leave
DataTable dt = (DataTable)this.dataGrid1.DataSource;
Boolean restore = false;

foreach ( DataRow row in dt.Rows ) {
  if ( (String)row["test"] == "errordata" ){
    restore = true;
    break;
  }
}

if (restore) {
  dt = new DataTable();
  dt = this.m_orgDt.Clone();
  for ( int i=0 ; i<this.m_orgDt.Rows.Count ;i++){
    dt.ImportRow(this.m_orgDt.Rows[i]);
  }
  this.dataGrid1.DataSource = dt;
  this.dataGrid1.Refresh();
}
なおこさん、お返事有難う御座います。

> まず、Windowsアプリケーションでしょうか?
> # ColumnChangedイベントがちょっと見つけられなかったのですが…

申し訳ありません、私の説明不足でした。
C#でWindowsアプリケーションを作成しており、
そこでDataGridを扱っています。
(実際には「Managed C++」で扱っています)

↓こちらで値を変更した時のイベントを発生させて、入力された値のチェックを行っています。
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpref/html/frlrfsystemdatadatatableclasscolumnchangedtopic.asp

> また、やりたい事は、以下の事で宜しいでしょうか?
> 1) DataTableにデータをForループで追加する。
>  ↓
> 2) 1)で作成したDataTableをDataGridにバインドする。
>  ↓
> 3) ユーザーがDataGridに入力し、
>   入力された値がエラー(範囲外)のデータであった場合、
>   1)で表示したデータに戻したい。

はい、この手順でグリッドのデータを更新したいと考えています。
データ自体は「ColumnChanged イベント」の内部で拾い、
System.Collections.ArrayListに格納しています。

エラー(範囲外)のデータであった場合、格納していた
System.Collections.ArrayListのデータをグリッドに再設定
という流れになります。

> ===============================================================
> ↑の事がやりたいのであれば、非効率ですが
> こんな感じではいかがでしょうか。
> (VBで書いたコードをテキストエディタでC#に書き直したので
>  間違ってるかもしれません(汗
> ===============================================================
> ■メンバ変数
> private DataTable m_orgDt;
>
> ■画面ロード時
> DataTable dt = new DataTable();
> dt.Columns.Add("test");
>
> this.m_orgDt = dt.Clone();
> for ( int i=0; i<=1000 ; i++) {
>   DataRow row = dt.NewRow();
>   row["test"] = i;
>   dt.Rows.Add(row);
>
>   // OriginalValueをとっておく
>   this.m_orgDt.ImportRow(row);
> }
> this.dataGrid1.DataSource = dt;
> this.dataGrid1.Refresh();
>
> ■dataGrid1.CurrentCellChanged と dataGrid1.Leave
> DataTable dt = (DataTable)this.dataGrid1.DataSource;
> Boolean restore = false;
>
> foreach ( DataRow row in dt.Rows ) {
>   if ( (String)row["test"] == "errordata" ){
>     restore = true;
>     break;
>   }
> }
>
> if (restore) {
>   dt = new DataTable();
>   dt = this.m_orgDt.Clone();
>   for ( int i=0 ; i<this.m_orgDt.Rows.Count ;i++){
>     dt.ImportRow(this.m_orgDt.Rows[i]);
>   }
>   this.dataGrid1.DataSource = dt;
>   this.dataGrid1.Refresh();
> }

なおこさんのコードを参考に(と言ってもほとんどそのままですが)
試してみたのですが、入力が全く受け付けなくなってしまいました…。

「ColumnChangedイベント」の処理中にグリッドデータを
更新するのは止めるべきなのでしょうか?
キーイベントなどからグリッドデータを更新する関数を
呼んだ場合は特に問題が発生しないのです。
お世話になります。

■No13336に返信(irvさんの記事)
では、RowChangedはどうでしょうか。
先ほどのLoad時の中で使っている変数dtをm_dtに変更し、

private DataTable m_dt;
this.m_dt.RowChanged += new DataRowChangeEventHandler(m_dt_RowChanged);

こんな感じで、宣言しておいて

private void m_dt_RowChanged(object sender, DataRowChangeEventArgs e)
{
  if ((String)e.Row["test"] == "aaa")
  {
    this.m_dt = new DataTable();
    this.m_dt = this.m_orgDt.Clone();
    for ( int i=0 ; i<this.m_orgDt.Rows.Count ;i++)
    {
      this.m_dt.ImportRow(this.m_orgDt.Rows[i]);
    }
    this.dataGrid1.DataSource = this.m_dt;
    this.dataGrid1.Refresh();
  }
}
なおこ(・∀・)さん、再びお返事有難う御座います。

イベントを「RowChanged」に変更してみたところ、
正常に動作するようになりました。

まだまだ勉強不足だな、と改めて実感しました。
本当に有難う御座います。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板