- PR -

DataBindingした場合の値の変更

投稿者投稿内容
toppo
ベテラン
会議室デビュー日: 2003/10/28
投稿数: 89
お住まい・勤務地: 東京・池袋
投稿日時: 2004-10-31 18:51
toppoです。

自作クラスのプロパティと、テキストボックスをデータバインドした場合に、
GUIからの値の変更を自作クラス自身が知る事は出来るのでしょうか?

というのも、
txtBox1.DataBindings.Add( "Text", this.Hoge, "Value" );
というように、Hogeクラス(FormにはHogeというHogeクラスの
インスタンスにアクセスするプロパティが用意してあります。)
のValueプロパティとバインドしています。
GUIから値を変更しても、HogeクラスのValueプロパティの
setブロックに処理が入らないようです。

Hogeクラスが内部で状態の変更を受けて処理をしたいのですが、
状態の変更を知る方法はあるのでしょうか?

よろしくお願いします。



[ メッセージ編集済み 編集者: toppo 編集日時 2004-10-31 18:51 ]
toppo
ベテラン
会議室デビュー日: 2003/10/28
投稿数: 89
お住まい・勤務地: 東京・池袋
投稿日時: 2004-11-01 00:15
toppoです。

自己レスです。
値の変更を知りたいという事でしたが、
DataBindingをしたときの動作が良く分からなくなってきました。

以下ソースを示します。

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApplication1
{
/// <summary>
/// Form1 の概要の説明です。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.ComboBox comboBox1;

private ValueClass valueClass = new ValueClass();
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;

public ValueClass DataSorce
{
get{ return valueClass; }
set{ valueClass = value;}
}
/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Windows フォーム デザイナ サポートに必要です。
//
InitializeComponent();

// コンボボックスへの設定
this.comboBox1.DataSource = ComboValueClass.ComboList;
this.comboBox1.ValueMember = ComboValueClass.ValueMenberName;
this.comboBox1.DisplayMember = ComboValueClass.DisplayMenberName;

// テキストボックスにバインド
this.textBox1.DataBindings.Add( "Text", this.DataSorce, "Hoge" );
// コンボボックスにバインド
this.comboBox1.DataBindings.Add( "SelectedValue", this.DataSorce, "Foo" );

}

/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows フォーム デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(40, 24);
this.textBox1.Name = "textBox1";
this.textBox1.TabIndex = 0;
this.textBox1.Text = "";
//
// comboBox1
//
this.comboBox1.Location = new System.Drawing.Point(48, 88);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(121, 20);
this.comboBox1.TabIndex = 1;
//
// button1
//
this.button1.Location = new System.Drawing.Point(56, 160);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(136, 23);
this.button1.TabIndex = 2;
this.button1.Text = "DataSorceの値を表示";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(56, 200);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(136, 23);
this.button2.TabIndex = 3;
this.button2.Text = "DataSorceに値を設定";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.comboBox1);
this.Controls.Add(this.textBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void button1_Click(object sender, System.EventArgs e)
{
MessageBox.Show( this.DataSorce.Hoge );
MessageBox.Show( this.DataSorce.Foo );
}

private void button2_Click(object sender, System.EventArgs e)
{
this.DataSorce.Hoge = "変更しました。";
this.DataSorce.Foo = "03";
this.Refresh();
this.comboBox1.Refresh();
this.textBox1.Refresh();
// this.comboBox1.Visible = false;
// this.comboBox1.Visible = true;
// this.textBox1.Visible = false;
// this.textBox1.Visible = true;
}

/// <summary>
/// コンボボックスの要素を表すクラス
/// </summary>
public class ComboValueClass
{

/// <summary>
/// ValueMember対応プロパティ名称
/// </summary>
private static string valueMemberName = "Code";
public static string ValueMenberName
{
get{ return valueMemberName;}
}
/// <summary>
/// DisplayMenber対応プロパティ名称
/// </summary>
private static string displayMemberName = "Name";
public static string DisplayMenberName
{
get{ return displayMemberName;}
}
/// <summary>
/// リストクラス保持配列
/// </summary>
private static IList list = null;
public static IList ComboList
{
get
{
if ( list == null )
{
list = new ArrayList();
list.Add( new ComboValueClass( "01", "Test01" ) );
list.Add( new ComboValueClass( "02", "Test02" ) );
list.Add( new ComboValueClass( "03", "Test03" ) );
list.Add( new ComboValueClass( "04", "Test04" ) );
}
return list;
}
}

// コード
private string code_;
// 名称
private string name_;

/// <summary>
/// コンストラクタ
/// </summary>
public ComboValueClass( string code, string name )
{
this.code_ = code;
this.name_ = name;
}

/// <summary>
/// コードの取得及び設定
/// </summary>
public string Code
{
get{ return this.code_; }
set{ this.name_ = value; }
}

/// <summary>
/// 名称の取得及び設定
/// </summary>
public string Name
{
get{ return this.name_; }
set{ this.name_ = value; }
}
}
/// <summary>
/// ValueClass の概要の説明です。
/// </summary>
public class ValueClass
{
private string hoge = "初期値";
private string foo = string.Empty;
public ValueClass()
{
}

public string Hoge
{
get
{
return hoge;
}
set
{
hoge = value;
}
}
public string Foo
{
get
{
return foo;
}
set
{
foo = value;
}
}
}
}
}
上記のソースを実行して、[DataSorceの値を設定]ボタンを押しても
表示上変わりません。[DataSorceの値を表示]ボタンを押すと、
ちゃんと設定されています。

Refresh()をしても、ちゃんと表示されず、
Visible = false;
Visible = true;
とすると、ちゃんと表示されます。

ただ、Visibleをfalse->trueとするなんていうのは、
気持ち悪いソースですよね。

直ぐに表示を反映させるには何か記述が足りないのか、
それとも、こうするしかないのでしょうか?

ご存知の方、是非ご教授下さい。
よろしくお願いします。







にしざき
ぬし
会議室デビュー日: 2003/06/30
投稿数: 304
投稿日時: 2004-11-01 08:52
経験では、
Foo クラスの Bar プロパティをバインドするときは
public event EventHandler BarChanged
が必要そうです。
コード:
public class Foo {
  private string bar;
  public string Bar {
    get {
      return bar;
    }
    set {
      if (bar != value) {
        bar = value;
        OnBarChanged(EventArgs.Empty);
      }
    }
  }
  public event EventHandler BarChanged;
  protected virtual OnBarChanged(EventArgs e) {
    if (BarChanged != null)
      BarChanged(this, e);
  }
}


これで、プロパティ Bar をうまくバインドできると思います。
toppo
ベテラン
会議室デビュー日: 2003/10/28
投稿数: 89
お住まい・勤務地: 東京・池袋
投稿日時: 2004-11-01 10:55
toppoです。

にしざきさん。ありがとうございます。
これならFooの変化に対して、外部から、処理を記述する事ができますね。

私の投稿を見直していたのですが、質問内容が1つに絞れていませんでした。
最初に投稿した問題については、私の勘違いでした。
返信しようと試みてくれていた方には大変失礼致しました。

ですので、1つめの質問及び、文中のソースコメントは無視してください。

問題は2つめの質問で、バインド先のオブジェクトの内部状態が変わったときに、
表示が直ぐに変わってくれないという問題です。
未だに、良い解決法が分からない状態です。

宜しくお願いします。
nanbu
大ベテラン
会議室デビュー日: 2004/08/19
投稿数: 178
投稿日時: 2004-11-01 12:20
引用:

toppoさんの書き込み (2004-11-01 10:55) より:
問題は2つめの質問で、バインド先のオブジェクトの内部状態が変わったときに、
表示が直ぐに変わってくれないという問題です。
未だに、良い解決法が分からない状態です。



南部です。

にしざきさんの投稿で、解決済みと思われますが?
toppo
ベテラン
会議室デビュー日: 2003/10/28
投稿数: 89
お住まい・勤務地: 東京・池袋
投稿日時: 2004-11-01 13:46
toppoです。

引用:

nanbuさんの書き込み (2004-11-01 12:20) より:
南部です。

にしざきさんの投稿で、解決済みと思われますが?



私、何か勘違いしているでしょうか?
以下のように変更してみましたが、
最初に、[DataSourceに値を設定]ボタンを押しても、
内部の値は変わっているのに、表示が変わりませんでした。
何か不足しているのでしょうか?

this.comboBox1.Visible = false;
this.comboBox1.Visible = true;
this.textBox1.Visible = false;
this.textBox1.Visible = true;
のようにすると、直ぐに反映されるのは、
2004-11-01 00:15の投稿時と変わっていません。

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApplication1
{
/// <summary>
/// Form1 の概要の説明です。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.ComboBox comboBox1;

private ValueClass valueClass = new ValueClass();
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;

public ValueClass DataSorce
{
get{ return valueClass; }
set{ valueClass = value;}
}
/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Windows フォーム デザイナ サポートに必要です。
//
InitializeComponent();

// コンボボックスへの設定
this.comboBox1.DataSource = ComboValueClass.ComboList;
this.comboBox1.ValueMember = ComboValueClass.ValueMenberName;
this.comboBox1.DisplayMember = ComboValueClass.DisplayMenberName;

// テキストボックスにバインド
this.textBox1.DataBindings.Add( "Text", this.DataSorce, "Hoge" );
// コンボボックスにバインド
this.comboBox1.DataBindings.Add( "SelectedValue", this.DataSorce, "Foo" );

}

/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows フォーム デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(40, 24);
this.textBox1.Name = "textBox1";
this.textBox1.TabIndex = 0;
this.textBox1.Text = "";
//
// comboBox1
//
this.comboBox1.Location = new System.Drawing.Point(48, 88);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(121, 20);
this.comboBox1.TabIndex = 1;
//
// button1
//
this.button1.Location = new System.Drawing.Point(56, 160);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(136, 23);
this.button1.TabIndex = 2;
this.button1.Text = "DataSorceの値を表示";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(56, 200);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(136, 23);
this.button2.TabIndex = 3;
this.button2.Text = "DataSorceに値を設定";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.comboBox1);
this.Controls.Add(this.textBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void button1_Click(object sender, System.EventArgs e)
{
MessageBox.Show( this.DataSorce.Hoge );
MessageBox.Show( this.DataSorce.Foo );
}

private void button2_Click(object sender, System.EventArgs e)
{
this.DataSorce.Hoge = "変更しました。";
this.DataSorce.Foo = "03";
this.Refresh();
this.comboBox1.Refresh();
this.textBox1.Refresh();
// this.comboBox1.Visible = false;
// this.comboBox1.Visible = true;
// this.textBox1.Visible = false;
// this.textBox1.Visible = true;
}

/// <summary>
/// コンボボックスの要素を表すクラス
/// </summary>
public class ComboValueClass
{

/// <summary>
/// ValueMember対応プロパティ名称
/// </summary>
private static string valueMemberName = "Code";
public static string ValueMenberName
{
get{ return valueMemberName;}
}
/// <summary>
/// DisplayMenber対応プロパティ名称
/// </summary>
private static string displayMemberName = "Name";
public static string DisplayMenberName
{
get{ return displayMemberName;}
}
/// <summary>
/// リストクラス保持配列
/// </summary>
private static IList list = null;
public static IList ComboList
{
get
{
if ( list == null )
{
list = new ArrayList();
list.Add( new ComboValueClass( "01", "Test01" ) );
list.Add( new ComboValueClass( "02", "Test02" ) );
list.Add( new ComboValueClass( "03", "Test03" ) );
list.Add( new ComboValueClass( "04", "Test04" ) );
}
return list;
}
}

// コード
private string code_;
// 名称
private string name_;

/// <summary>
/// コンストラクタ
/// </summary>
public ComboValueClass( string code, string name )
{
this.code_ = code;
this.name_ = name;
}

/// <summary>
/// コードの取得及び設定
/// </summary>
public string Code
{
get{ return this.code_; }
set{ this.name_ = value; }
}

/// <summary>
/// 名称の取得及び設定
/// </summary>
public string Name
{
get{ return this.name_; }
set{ this.name_ = value; }
}
}
/// <summary>
/// ValueClass の概要の説明です。
/// </summary>
public class ValueClass
{
private string hoge = "初期値";
private string foo = string.Empty;
public ValueClass()
{
}

public string Hoge
{
get
{
return hoge;
}
set
{
if (hoge != value)
{
hoge = value;
OnHogeChanged(EventArgs.Empty);
}
}
}
public event EventHandler HogeChanged;
protected virtual void OnHogeChanged(EventArgs e)
{
if (HogeChanged != null)
HogeChanged(this, e);
}

public string Foo
{
get
{
return foo;
}
set
{
foo = value;
}
}
}
}
}


[ メッセージ編集済み 編集者: toppo 編集日時 2004-11-01 14:02 ]
nanbu
大ベテラン
会議室デビュー日: 2004/08/19
投稿数: 178
投稿日時: 2004-11-01 14:36
南部です。

投稿日時: 2004-11-01 13:46 のコードで確かめてみましたが、
[DataSourceに値を設定]ボタンクリックで、
一番上のテキストボックスのテキストが
「変更しました。」
にすぐ更新されました。

#コピペしたんで、同一コード。

動作環境は、
Window 2000 Pro
.NET Framework1.1 SP1
です。

#環境!? まじ?
toppo
ベテラン
会議室デビュー日: 2003/10/28
投稿数: 89
お住まい・勤務地: 東京・池袋
投稿日時: 2004-11-01 15:04
toppoです。

すみません。
勘違いだったようです。
無事動作しました。

もう少し付き合ってもらいたいのですが、
私の脳みそではこの動作の説明がつきません。

ValueChangeのevent HogeChanged は
いつnullじゃなくなるのでしょうか?

だれも、valueClass.HogeChanged += xxxxx
のような事をしている訳ではないのに。。。

protected virtual void OnHogeChanged(EventArgs e)
{
  if (HogeChanged != null)
  {
    //※1
  HogeChanged(this, e);
  }
}
の※1の箇所に処理がいかないと思っていました。

また、仮に何らかのしくみで、nullじゃ無くなり、処理が
※1に行ったとして、勝手に定義した、HogeChangedという
イベントを誰がどのように処理しているのでしょうか?

文献でも良いので、教えていただけないでしょうか?

スキルアップ/キャリアアップ(JOB@IT)