アプリ版:「スタンプのみでお礼する」機能のリリースについて

こんにちは.お世話になっております.
まず,質問を開いて頂いてありがとうございます.

Windows7 HomePremium 64bit,Microsoft Visual C# 2010 Express
という環境の下,趣味でWindowsフォームアプリケーションを作成しております.

本日は,DataGridViewへ関連付けたデータの更新について質問させていただきました.
問題としては,一度プログラム上で
 dataGridView1.DataSource = ds;
 dataGridView1.DataMember = ds.Tables[0].TableName;
 ※ dsはDataSetクラスのインスタンスです.
とデータを関連づけた後に,ds.Table[0]に対して逆シリアライズをしてデータを更新してもDataGridViewの内容が更新されない,というものです.

更新後にスウォッチで見るとDataGridViewのDataSourceの内容は更新されているにも関わらずデータは更新しません.
これについて解決策・打開案をご存知の方がいらっしゃいましたらご教授ください.

蛇足かもしれませんが,他の質問を調べている際「デザイナでDataSourceを設定しているとプログラム上でそれを更新できない」という原因を元に解決した質問がありましたが,当方はデザイナでは設定しておりません.

以上です.よろしくお願いいたします.

A 回答 (3件)

正直な所、最初の回答に記載した後者の状況であって、


バインドし直せばよいのだろうなと思っていましたが、
バインド設定のクリアと再設定もしていたのですね。

試して見ましたが、なかなか腑に落ちない動作になりますね。
DataSet.Tables.Clear() ではなく DataSet.Reset() を行うようにしてみたところ、
DataGridView の内容は空になりました。
データソースをクリアしても DataSet.DefaultViewManager あたりが
何処かに保持されているのでしょうか。。よくわかりません。

DataGridView への DataTable のバインドは、
DataSet を利用して DataSource および DataMember プロパティを設定する以外に
DataSource に DataTable を直接指定する利用方法もありますが、
それを試して見たところ、1度目は上手くいったように見えますが、
その後 DataSource を何に変更しても表示が変わらないというおかしな状態になりました。

データバインドはバインドしたインスタンスの中身を更新することで
表示に反映という利用方法が多いかとは思いますが、
バインドするオブジェクト自体を切り替えるのも
結構普通の利用方法だと思うのでなにかやり方があるのかもしれませんが、
見つけられませんでした。


DataSetを作り直す以外の回避方法としては、
データの持ち方や保存データの仕様などによって
利用可能かはわかりませんが以下のような手もありそうです。

・DataTable.WriteXml() で保存したデータを DataTable.ReadXml() を使って
 バインドしたDataTableインスタンスをそのままに中身を更新する。
 ReadXml() 前にテーブルのスキーマ(列)が準備されている必要があり、
 スキーマが変化する場合は利用できない。
 型付きデータセットの場合はいいかも?

・BindingSourceを介する。
 DataGridViewにBindingSourceをバインドし、
 BindingSourceにデータセットをバインドする。
 イメージとしては以下のような感じ。

private DataSet testDataSet = new DataSet();
private BindingSource dataBinder = new BindingSource();

private void init()
{
this.dataBinder.DataSource = this.testDataSet;
this.dataBinder.DataMember = this.testDataSet.Tables[0].TableName;

this.dataGridView1.DataSource = this.dataBinder;
}

private void load()
{
try
{
this.dataBinder.DataSource = null;
this.dataBinder.DataMember = null;

deserialize();
}
finally
{
this.dataBinder.DataSource = this.testDataSet;
this.dataBinder.DataMember = this.testDataSet.Tables[0].TableName;
}
}

○おまけ
BindingListが話に出ていますので少し触れますと、
これは自作のデータクラスなどのリストをバインドする際に結構便利です。
BindingList<>は普通のList<>などと同じように任意のデータクラスを要素として使えますが、
そのままDataSourceにバインドすれば、BindingList<>への要素の増減が
自動的に表示に反映されます。
ただし、ソートやフィルタを利用する場合は自分で実装する必要があり、
要素の数ではなく要素(データクラス)内のフィールド(プロパティ)変化をリアルタイムに反映したい場合は
データクラスが INotifyPropertyChanged を実装する必要があります。
そのあたりを必要としない読み取り専用データのリストを表示したい場合などは便利です。

またそのほかに、上でも少し触れている BindingSource はいろいろなデータソースと
コントロールの間を仲介することが出来ます。
たとえば変化の通知手段を保たない List<> とコントロールの間に挟み、
BindingSource に対してデータ操作を行うことで、
表示にもList<>にも更新を行う、といったような使い方もできます。
(外付けのラッパーのようなイメージ)
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます.

BindingSourceをテストクラスで使ってみました!
まさにこの動作を求めていた!という感じで感激しております.

BindingList<>も少し触ってみましたが,まだまだ可能性がありそうでワクワクしますね!
BindingSourceとともにこれから色々触って勉強していこうと思います.

質問内容について,解決しましたのでこれで質問も締め切らせて頂きます.
ありがとうございました!

お礼日時:2013/12/10 22:45

DataSourceを一度nullにしてDataSetを再バインドすると表示されます。



私は使用したことがありませんが、
DataSetではなくBindingListを使えばこのような手間はいらないようですね。
    • good
    • 0
この回答へのお礼

回答ありがとうございます.
No1の方のお礼欄にも書かせていただいたのですが,同じものを割り当てても更新されませんでした.
ただし,一旦DataSetのインスタンスをDispose()して再度インスタンス化→逆シリアライズして割り当てると更新が行われました.

回答の文面からは,そんなことをしなくても良さそうに思われるのですが,その点についてももし私の方法で間違いがありましたらご教授頂けると幸いです.

BindingListについても調べてみます.
ありがとうございました!

お礼日時:2013/12/09 22:02

ご質問の内容では、具体的にどういうコードを書いて


データソースを更新しているか書かれて居ませんので、
コードの書き方が悪いんじゃないでしょうか?
というぐらいしかアドバイス出来ることはありませんが。。。


実際の状況が不明なので書くだけ無駄になるかもしれませんが、
一応予想をしてもう少し言うとすれば、

DataGridViewがデータソースの更新を表示に反映できるのは、
ただデータバインドをしているからではなく、
データソースを更新した時、データソース自身が通知を行い、
DataGridViewはそれを受けてデータの再読み出し・再表示を行うからです。
データソースの更新通知が無効化されていればリアルタイムでの更新は行われなくなります。
(BeginLoadData()してEndLoadData()をしていない、など)

あるいは、データバインドで参照するデータソースは、
DataSource や DataMemberを設定した時点のデータを参照するため、
あとから同じテーブル名で別のインスタンスを作って
データセット内のテーブルを入れ替えた場合などには、
DataGridViewは古いインスタンス側を参照しているため
データセット内のものを参照していない、ということにもなりえます。

この回答への補足

情報不足で申し訳ありません.
以下のようにコードを書きました.

<逆シリアライズ部分(データ管理するクラス内に定義した関数)>
public void desirialize()
{
 DataTable dt = new DataTable(TABLE_NAME);

 System.IO.StreamReader sr = null;
 System.Xml.Serialization.XmlSerializer serializer =
  new System.Xml.Serialization.XmlSerializer(dt.GetType());

 try
 {
  this.Tables.Clear();

  sr = new System.IO.StreamReader(FILENAME);
  dt = (DataTable)serializer.Deserialize(sr);

  this.Tables.Add(dt);
 }
 catch (Exception ex)
 {
  throw ex;
 }
 finally
 {
  if (sr != null)
  {
   sr.Close();
  }
 }
}

というクラスをインスタンス化し,

<呼び出し部(上のクラスをインスタンス化したクラス内のボタンクリックイベント内)>
dataGridView1.DataMember = "";
dataGridView1.DataSource = null;

dst.desirialize();

dataGridView1.DataSource = ds;
dataGridView1.DataMember = ds.Tables[0].TableName;

以上です.よろしくお願いいたします.

補足日時:2013/12/09 21:54
    • good
    • 0
この回答へのお礼

補足の文章,コード部分の締めの言葉を忘れておりました.
失礼な文章になってしまい申し訳ありません.

DataGridViewがどのようなタイミングでデータの更新・表示を行うのかは知りませんでした.
ありがとうございます.

補足に書き忘れておりましたが,
DataSourceとDataMemberを一旦削除して,削除したものと同じものを割り当てても更新がされなかったのですが,一旦DataSetのインスタンスをDispose()して再度インスタンス化→逆シリアライズして割り当てると更新が行われました.

これは正規の方法なのでしょうか?
もっと正しい(上手い)やり方があればご教授いただければ幸いです.

お礼日時:2013/12/09 21:59

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A