1 はじめに
フォームアプリケーションで下図のように配列とかコレクションの要素をコントロールにバインドしたいと思ったのですが、フォームデザイナーではできないようです。
List内の現在位置(CurrencyManager#Position)だけならデザイナーからバインドできることは確認しました。
またコードを書くなら色々できそうなことは判りました。
色々試してみたのでその結果を書いてみます。
2 コードによるデータバインディング
コードによるデータバインディングはControlBindingsCollection.Add
を使用しました。
Add は System.Windows.Forms.Binding
を返すメソッドで以下のように記述します。
Control.DataBindings.Add (string propertyName, object dataSource, string dataMember);
- `propertyNameString `
- バインドするコントロール プロパティの名前。
- `dataSourceObject `
- データ ソースを表す Object。
- `dataMemberString `
- バインド先のプロパティまたはリスト。
Formおよびデータソースのコードは以下の通りです。
public partial class Form1 : Form
{
private CurrencyManager currencyManager1 = null;
private Food _food;
public Form1()
{
InitializeComponent();
_food = new Food();
foodBindingSource.DataSource = _food;
BindingSource binds = new BindingSource();
binds.DataSource = _food.fruits;
//List<Fruits> fruitsの現在行を管理
currencyManager1 = (CurrencyManager)this.BindingContext[_food.fruits];
//dataSourceObjectにSystem.Windows.Forms.BindingSource(binds[])を指定
textBoxName1.DataBindings.Add("Text", binds[0], "Name");
textBoxQuant1.DataBindings.Add("Text", binds[0], "Quantity");
//dataSourceObjectにList(food.fruits[])を指定
textBoxName2.DataBindings.Add("Text", _food.fruits[1], "Name");
textBoxQuant2.DataBindings.Add("Text", _food.fruits[1], "Quantity");
//dataSourceObjectにインデクサ(food[])を指定
textBoxName3.DataBindings.Add("Text", _food[2], "Name");
textBoxQuant3.DataBindings.Add("Text", _food[2], "Quantity");
textBoxCurName.DataBindings.Add("Text", _food.fruits, "Name");
textBoxCurQuant.DataBindings.Add("Text", _food.fruits, "Quantity");
textBoxCurQuant2.DataBindings.Add("Text", binds, "Quantity");
comboBox1.DataSource = _food.fruits;
comboBox1.DisplayMember = "Name";
}
private void buttonMovePosition_Click(object sender, EventArgs e)
{
if (currencyManager1.Position < (_food.fruits.Count - 1))
currencyManager1.Position++;
else
currencyManager1.Position = 0;
}
private void buttonCountUp_Click(object sender, EventArgs e)
{
_food.fruits[currencyManager1.Position].Quantity += 1;
}
public class Food
{
public List<Fruit> fruits;
public Food()
{
fruits = new List<Fruit>();
fruits.Add(new Fruit("apple",10));
fruits.Add(new Fruit("orange", 20));
fruits.Add(new Fruit("peach", 30));
}
public Fruit this[int index]
{
get
{
return fruits[index];
}
}
public class Fruit : INotifyPropertyChanged
{
private string _name;
private int _quantity;
public Fruit(string name, int quantity)
{
_name = name;
_quantity = quantity;
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
OnPropertyChanged();
}
}
public int Quantity
{
get
{
return _quantity;
}
set
{
_quantity = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
3 結果
以下の観点で評価しました。
(1)初期表示が意図した表示になるか(○:なる、×:ならない)
(2)プロパティ変更時コントロールに反映されるか(○:なる、×:ならない、-:該当しない等)
(3)現在行変更時関連するコントロールの表示が連動するか(○:なる、×:ならない、-:該当しない等)
コントロール | データソース | バインド先 | 初期表示 | プロパティ変更時 | 現在行変更時 |
---|---|---|---|---|---|
textBoxQuant1 | binds[0] | Quantity | ○ | ○ | - |
textBoxQuant2 | _food.fruits[1] | Quantity | ○ | ○ | - |
textBoxQuant3 | _food[2] | Quantity | ○ | ○ | - |
comboBox1 | _food.fruits | - | ○ | - | ○ |
textBoxCurQuant | _food.fruits | Quantity | ○ | × | ○ |
textBoxCurQuant2 | binds | Quantity | ○ | ○ | ○ |
以下が確認した画面ですが、「数量更新」でQuantityプロパティを変更しても何故かtextBoxCurQuantの値が更新されません。
まあ、BindingSource を使えば問題は回避されるのですが、まだまだ双方向バインディングとか理解不足です。
4 主な参考サイト
- Data Binding in .NET / C# Windows Forms
https://www.akadia.com/services/dotnet_databinding.html
5 環境
- 開発環境 --- Visual Studio Community 2017