System.Windows.Forms.Controlクラスには、データバインディングが
行えるようにDataBindingsプロパティが公開されています。
これを行うと、データオブジェクトの特定のプロパティと
コントロールのデータが連結(バインディング)されます。
つまり、オブジェクトの値とコントロールが同期するようになります。
やり方は、簡単で以下のようにします。
class Model{ string _val; public string Val{ get{ return _val; } set{ _val = value; } } } Model _m = new Model(); TextBox t1 = new TextBox(); t1.DataBindings.Add(new Binding("Text", _m, "Val"));
これで、バインディングが行われるようになります。
t1.DataBindings.Add(new Binding("Text", _m, "Val"));
の部分で、TextBoxのTextプロパティと_mのValプロパティの
値をバインディングしています。
こんな感じ。
コントロール.DataBindings.Add(new Binding(コントロール側のプロパティ名, バインド先オブジェクト, バインド先オブジェクトのプロパティ名);
Javaでいうと、JGoodiesのBindingフレームワークのような感じです。
これをうまく使うと、よくある
_m.Val = t1.Text; (以下、入力項目の値をモデルオブジェクトに移し変えるコードが続く)
のような作業がなくなります。
画面で入力されたデータがそのままモデルオブジェクトにも連結されますので。
(補足)
ただし、上記の場合ModelオブジェクトはINotifyPropertyChangedインターフェースを
実装していないので、コントロール側からデータソース側(Modelオブジェクト)側への
連携(変更通知)は行われますが、データソース側の値を変更した場合に、コントロール側への変更通知
をおこなうことはできません。
以下サンプルです。
// vim:set ts=4 sw=4 et ws is nowrap ft=cs: using System; using System.Windows.Forms; namespace Gsf.Samples.WinForms{ /// <summary> /// サンプルデータモデルクラスです。 /// </summary> class Model{ string _textValue1; string _textValue2; public string TextValue1{ get{ return _textValue1; } set{ _textValue1 = value; } } public string TextValue2{ get{ return _textValue2; } set{ _textValue2 = value; } } public override string ToString(){ return string.Format("{0}, {1}", _textValue1, _textValue2); } } /// <summary> /// Controlのデータバインディングのサンプルです。 /// </summary> /// <remarks> /// Controlクラスは、データ連結が出来るように /// DataBindingsプロパティを公開しています。 /// このプロパティにBindingインスタンスを追加することで /// 特定のオブジェクトおよびデータソースとコントロール /// を連結することができます。 /// </remarks> public class DataBindingSample : Form{ Model _model; public DataBindingSample(){ _model = new Model(); InitializeComponent(); } protected void InitializeComponent(){ TextBox t1 = new TextBox(); t1.Dock = DockStyle.Fill; // // データバインディング設定 // // 以下の設定を行うことで、Modelインスタンスの // TextValue1プロパティとTextBoxのTextプロパティが // 連結されます。 // // つまり、画面上で入力されたデータがTextBoxにも // Modelインスタンスにも設定されるようになります。 // t1.DataBindings.Add(new Binding("Text", _model, "TextValue1")); TextBox t2 = new TextBox(); t2.Dock = DockStyle.Fill; // // データバインディング設定. // t2.DataBindings.Add(new Binding("Text", _model, "TextValue2")); Button b1 = new Button(); b1.Text = "Push"; b1.Click += delegate(object s, EventArgs e){ // // ちゃんとモデルオブジェクトにもデータが格納されているか確認. // MessageBox.Show(_model.ToString()); }; /////////////////////////////////////// // // TableLayoutPanel // TableLayoutPanel p = new TableLayoutPanel(); p.Dock = DockStyle.Fill; p.ColumnCount = 2; p.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); p.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); p.Controls.Add(t1); p.Controls.Add(t2); p.Controls.Add(b1, 1, 2); Controls.Add(p); MaximizeBox = false; Size = new System.Drawing.Size(200, 100); } [STAThread] static void Main(){ Application.Run(new DataBindingSample()); } } }
[補足]
Binding作成時に指定するプロパティ名ですが、単一のプロパティだけでなく
そのプロパティが示すオブジェクトのプロパティも指定できます。
つまり、階層をたどって指定することができます。
ナビゲーションパスはドットで区切って表現します。
例)
class Address{ string address1; string address2; (略) public string Address1{ (略) } } class User{ string name; Address address; (略) public Address UserAddress{ (略) } }
という構造になっているとして、バインディング先オブジェクトにUserのUserAddressプロパティ
から取得できるAddressクラスのAddress1プロパティを指定したい場合は、
new Binding("Text", user, "UserAddress.Address1");
と指定します。
javaでいうと、OGNLでナビゲーションパスを指定しているのと似ています。