none
データバインディングというのがよくわかりません。 RRS feed

  • 質問

  • SqlServer2012Express とVisualStudio2012C#で、データベースプログラムを作ろうと試みています。

    DataGridView1で選択した行を他の処理に渡したくて、ネットで調べて、次のようにしてみました。

     

       DataSet ds = new DataSet();
       SqlDataAdapter adpt = new SqlDataAdapter();
       DataTable tbl = new DataTable("Movies");
       ds.Tables.Add(tbl);
       for(int i=0; i<DataGrifView1.ColumnCount; i++){
          tbl.Columns.Add(DataGridVew1.Columns[i].Name,DataGridView1.Columns[i].ValueType);
       }
       foreach(DataGridViewRow dr in DataGridView1.SelectedRows){
          DataRowView rv= (DataRowView)dr.DataBoundItem;
          tbl.ImportRow(rv.Row);
       }

    ここで、出来たDataSet dsを、他のフォームに渡しました。そのフォームにはDataBindingNavigator1と、内容を表示するためのtextBox1から3があります。フォームLoadで次のように
    ナビゲータと各テキストに設定しました。

    BindingSource1.DataSource = ds;
    BindingSource1.DataMember = "Movies";
    DataBindingNavigator1.BindingSource = BindingSource1;
    textBox1.DataBindings.Add(new Binding("Text", ds, "Movies.邦題"));
    textBox2.DataBindings.Add(new Binding("Text", ds, "Movies.原題"));
    textBox3.DataBindings.Add(new Binding("Text", ds, "Movies.読み"));

    DataGridViewの複数の行を選択して、この処理を行うと、ナビゲータには、選択した行数分だけのレコード数の分母が表示され、各テキストにはそれぞれのレコードの内容の内の一件分が表示されています。

    Q1:

    しかし、ここで、ナビゲータの進むボタンを押してみると、レコード位置を示す数(分子の方)が進むのに、テキストの内容が変化しません。何か、やり足りないのでしょうか?試しにDataGridViewを貼り付けてdatasourceにdsをセットすると、行数分のデータが表示され、ナビゲータの操作に応じて、表のセレクトも進んだりします。 

    2013年1月7日 19:05

回答

  • DataBindingNavigator1にバインドしているデータソースはBindingSource1ですが、textBox1~3にバインドしているデータソースはdsになってます。

    BindingSourceは、独自に「現在の選択位置」を管理する機能を持っており、同一のBindingSourceをデータソースとするコントロール間で選択アイテムを共有できます。逆に言うと、同一のBindingSourceではないオブジェクトをデータソースとしているコントロール間では選択アイテムを共有できません。

    // 最終的にはdsをデータソースとしているので、データ自体は共有されますが。

    • 回答としてマーク 佐伯玲 2013年1月9日 2:05
    2013年1月7日 23:41
  • データバインディングがよくわからないということですので、ざっと説明します。
    話を単純にするため、ここではバインドするデータソースをデータテーブルとします。

    さて、TextBoxにデータバインドを行うコードを書くと、裏では以下の仕組みが構築されます。

    BindingContext---CurrencyManager--Binding--データテーブル
                       |
                       |
                      TextBox

    データソースが同じである場合は、同じCurrencyManagerが使われます。例えば、以下のような感じです。

                        TextBox1
                         |
                         |
                      +--Binding1--+
    BindingContext---CurrencyManager--|       |---データテーブル
                      +--Binding2--+
                         |
                         |
                        TextBox2

    同じCurrencyManagerで管理することにより、TexgBox1とTextBox2の同期が取られます。
    BindingContextはCurrencyManagerを管理するためのクラスです。データソースが異なればCurrencyManagerは複数できます。また、同じデータソースを使っても、コントロールのグループ毎に同期を変えたい場合は、もう一つBindingContext以下を作成することになります。同じデータソースにバインドしていてもCurrencyManagerが違うので、CurrencyManager毎に同期が管理されます。

    と、ここまでは一昔前までの用いられていた方法で、バインディングのことをきちんと理解していないとなかなかやっかいであり、コードもわかりにくくなりがちでした。そこで、現在はBindingSourceクラスが追加されています。このクラスはCurrencyManagerをラップし、簡単に扱えるようにした便利クラスと考えても良いでしょう。
    Tolbieさんが上で書かれたコードである、
    textBox1.DataBindings.Add(new Binding("Text", ds, "Movies.邦題"));
    などは、私が上で説明したように裏でCurrencyManagerが自働的に作成され、バインディングはその配下に置かれています。
    一方、
    DataBindingNavigator1.BindingSource = BindingSource1;
    は、BindingSourceが独自にCurrencyManagerを持ち、よって、TextBoxのバインディングを管理しているCurrencyManagerとは異なるため、DataBindingNavigator1とTextBox1は同期しないのです。
    DataGridViewのことを書かれていますが、なぜDataGridViewでは同期するのか、これまでの説明で理解できるのではないかと思います。

    2013年1月8日 1:44
    モデレータ

すべての返信

  • DataBindingNavigator1にバインドしているデータソースはBindingSource1ですが、textBox1~3にバインドしているデータソースはdsになってます。

    BindingSourceは、独自に「現在の選択位置」を管理する機能を持っており、同一のBindingSourceをデータソースとするコントロール間で選択アイテムを共有できます。逆に言うと、同一のBindingSourceではないオブジェクトをデータソースとしているコントロール間では選択アイテムを共有できません。

    // 最終的にはdsをデータソースとしているので、データ自体は共有されますが。

    • 回答としてマーク 佐伯玲 2013年1月9日 2:05
    2013年1月7日 23:41
  • データバインディングがよくわからないということですので、ざっと説明します。
    話を単純にするため、ここではバインドするデータソースをデータテーブルとします。

    さて、TextBoxにデータバインドを行うコードを書くと、裏では以下の仕組みが構築されます。

    BindingContext---CurrencyManager--Binding--データテーブル
                       |
                       |
                      TextBox

    データソースが同じである場合は、同じCurrencyManagerが使われます。例えば、以下のような感じです。

                        TextBox1
                         |
                         |
                      +--Binding1--+
    BindingContext---CurrencyManager--|       |---データテーブル
                      +--Binding2--+
                         |
                         |
                        TextBox2

    同じCurrencyManagerで管理することにより、TexgBox1とTextBox2の同期が取られます。
    BindingContextはCurrencyManagerを管理するためのクラスです。データソースが異なればCurrencyManagerは複数できます。また、同じデータソースを使っても、コントロールのグループ毎に同期を変えたい場合は、もう一つBindingContext以下を作成することになります。同じデータソースにバインドしていてもCurrencyManagerが違うので、CurrencyManager毎に同期が管理されます。

    と、ここまでは一昔前までの用いられていた方法で、バインディングのことをきちんと理解していないとなかなかやっかいであり、コードもわかりにくくなりがちでした。そこで、現在はBindingSourceクラスが追加されています。このクラスはCurrencyManagerをラップし、簡単に扱えるようにした便利クラスと考えても良いでしょう。
    Tolbieさんが上で書かれたコードである、
    textBox1.DataBindings.Add(new Binding("Text", ds, "Movies.邦題"));
    などは、私が上で説明したように裏でCurrencyManagerが自働的に作成され、バインディングはその配下に置かれています。
    一方、
    DataBindingNavigator1.BindingSource = BindingSource1;
    は、BindingSourceが独自にCurrencyManagerを持ち、よって、TextBoxのバインディングを管理しているCurrencyManagerとは異なるため、DataBindingNavigator1とTextBox1は同期しないのです。
    DataGridViewのことを書かれていますが、なぜDataGridViewでは同期するのか、これまでの説明で理解できるのではないかと思います。

    2013年1月8日 1:44
    モデレータ
  • 「現在の選択位置」を知っているものを共有しないといけないという事ですね。

    バインディングソースとか、バインディングオブジェクトとか、まだ若干混乱しておりますが、なんとか現状が解決しそうです。

    ご教授ありがとうございました。

    2013年1月8日 6:14
  • Newでバインディングオブジェクトを作ると、データの位置を知っているものと別のものを使う事になってしまうのですね。

    DataBindings.Add("Text",BindingSource1,"カラム名");

    DataBindings.Addに、こういうコンストラクタがあることを知りました。これで、同じCurrencyManagerを使う事になるのですね。

    ご教授ありがとうございました。

    2013年1月8日 6:22