Windows フォーム データ バインディングの最も重要な概念の 1 つは、変更通知です。 データ ソースとバインドされたコントロールに常に最新のデータが含まれるようにするには、データ バインディングの変更通知を追加する必要があります。 具体的には、バインドされたコントロールに、データ ソースに加えられた変更が通知されるようにする必要があります。 データ ソースには、コントロールのバインドされたプロパティに加えられた変更が通知されます。
データ バインディングの種類に応じて、さまざまな種類の変更通知があります。
単一のコントロール プロパティがオブジェクトの 1 つのインスタンスにバインドされる単純なバインド。
リスト ベースのバインド。リスト内の項目のプロパティにバインドされた単一のコントロール プロパティ、またはオブジェクトのリストにバインドされたコントロール プロパティを含めることができます。
さらに、データ バインディングに使用する Windows フォーム コントロールを作成する場合は、PropertyName変更されたパターンをコントロールに適用する必要があります。 コントロールにパターンを適用すると、コントロールのバインドされたプロパティがデータ ソースに反映されます。
シンプルバインディングの変更通知
単純なバインドの場合、ビジネス オブジェクトは、バインドされたプロパティの値が変更されたときに変更通知を提供する必要があります。 ビジネス オブジェクトの各プロパティに対して PropertyNameChanged イベントを公開することで、変更通知を提供できます。 また、ビジネス オブジェクトを、BindingSource またはビジネス オブジェクトが INotifyPropertyChanged インターフェイスを実装し、プロパティの値が変更されたときに PropertyChanged イベントを発生させる優先メソッドを使用してコントロールにバインドする必要もあります。
INotifyPropertyChanged
インターフェイスを実装するオブジェクトを使用する場合、BindingSource
を使用してオブジェクトをコントロールにバインドする必要はありません。 ただし、BindingSource
を使用することをお勧めします。
リスト ベースのバインドの変更通知
Windows フォームは、バインドされたリストに依存して、プロパティの変更 と リストの変更 情報をバインドされたコントロールに提供します。
プロパティの変更 はリスト アイテムのプロパティ値の変更であり、リスト 変更 は、リストに削除または追加されたアイテムです。 そのため、データ バインディングに使用されるリストは、両方の種類の変更通知を提供する IBindingListを実装する必要があります。
BindingList<T> は、IBindingList
の一般的な実装であり、Windows フォームのデータ バインディングで使用するように設計されています。
BindingList
を実装するビジネス オブジェクトの種類を含む INotifyPropertyChanged を作成すると、PropertyChanged イベントが ListChanged イベントに自動的に変換されます。 バインドされたリストが IBindingList
でない場合は、BindingSource コンポーネントを使用して、オブジェクトのリストを Windows フォーム コントロールにバインドする必要があります。
BindingSource
コンポーネントは、BindingList
と同様のプロパティからリストへの変換を提供します。 詳細については、「方法: BindingSource と INotifyPropertyChanged インターフェイスを使用して変更通知を生成する」を参照してください。
カスタム コントロールの変更通知
最後に、コントロール側から、データにバインドするように設計された各プロパティの PropertyNameChanged イベントを公開する必要があります。 コントロール プロパティへの変更は、バインドされたデータ ソースに反映されます。 詳細については、「PropertyNameChanged パターンを適用する」を参照してください。
PropertyNameChanged パターンを適用する
次のコード例では、PropertyNameChanged パターンをカスタム コントロールに適用する方法を示します。 Windows フォーム データ バインディング エンジンで使用されるカスタム コントロールを実装するときにパターンを適用します。
// This class implements a simple user control
// that demonstrates how to apply the propertyNameChanged pattern.
[ComplexBindingProperties("DataSource", "DataMember")]
public class CustomerControl : UserControl
{
private DataGridView dataGridView1;
private Label label1;
private DateTime lastUpdate = DateTime.Now;
public EventHandler DataSourceChanged;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public object DataSource
{
get
{
return this.dataGridView1.DataSource;
}
set
{
if (DataSource != value)
{
this.dataGridView1.DataSource = value;
OnDataSourceChanged();
}
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public string DataMember
{
get { return this.dataGridView1.DataMember; }
set { this.dataGridView1.DataMember = value; }
}
private void OnDataSourceChanged()
{
if (DataSourceChanged != null)
{
DataSourceChanged(this, new EventArgs());
}
}
public CustomerControl()
{
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.label1 = new System.Windows.Forms.Label();
this.dataGridView1.ColumnHeadersHeightSizeMode =
System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.ImeMode = System.Windows.Forms.ImeMode.Disable;
this.dataGridView1.Location = new System.Drawing.Point(100, 100);
this.dataGridView1.Size = new System.Drawing.Size(500,500);
this.dataGridView1.TabIndex = 1;
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(50, 50);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(76, 13);
this.label1.TabIndex = 2;
this.label1.Text = "Customer List:";
this.Controls.Add(this.label1);
this.Controls.Add(this.dataGridView1);
this.Size = new System.Drawing.Size(450, 250);
}
}
' This class implements a simple user control
' that demonstrates how to apply the propertyNameChanged pattern.
<ComplexBindingProperties("DataSource", "DataMember")>
Public Class CustomerControl
Inherits UserControl
Private dataGridView1 As DataGridView
Private label1 As Label
Private lastUpdate As DateTime = DateTime.Now
Public DataSourceChanged As EventHandler
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Public Property DataSource() As Object
Get
Return Me.dataGridView1.DataSource
End Get
Set
If DataSource IsNot Value Then
Me.dataGridView1.DataSource = Value
OnDataSourceChanged()
End If
End Set
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Public Property DataMember() As String
Get
Return Me.dataGridView1.DataMember
End Get
Set
Me.dataGridView1.DataMember = Value
End Set
End Property
Private Sub OnDataSourceChanged()
If (DataSourceChanged IsNot Nothing) Then
DataSourceChanged(Me, New EventArgs())
End If
End Sub
Public Sub New()
Me.dataGridView1 = New System.Windows.Forms.DataGridView()
Me.label1 = New System.Windows.Forms.Label()
Me.dataGridView1.ColumnHeadersHeightSizeMode =
System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
Me.dataGridView1.ImeMode = System.Windows.Forms.ImeMode.Disable
Me.dataGridView1.Location = New System.Drawing.Point(19, 55)
Me.dataGridView1.Size = New System.Drawing.Size(550, 150)
Me.dataGridView1.TabIndex = 1
Me.label1.AutoSize = True
Me.label1.Location = New System.Drawing.Point(19, 23)
Me.label1.Name = "label1"
Me.label1.Size = New System.Drawing.Size(76, 13)
Me.label1.TabIndex = 2
Me.label1.Text = "Customer List:"
Me.Controls.Add(Me.label1)
Me.Controls.Add(Me.dataGridView1)
Me.Size = New System.Drawing.Size(650, 300)
End Sub
End Class
INotifyPropertyChanged インターフェイスを実装する
次のコード例は、INotifyPropertyChanged インターフェイスを実装する方法を示しています。 Windows フォームのデータ バインディングで使用されるビジネス オブジェクトにインターフェイスを実装します。 実装されると、インターフェイスは、ビジネス オブジェクトのプロパティの変更をバインドされたコントロールと通信します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
// Change the namespace to the project name.
namespace binding_control_example
{
// This form demonstrates using a BindingSource to bind
// a list to a DataGridView control. The list does not
// raise change notifications. However the DemoCustomer1 type
// in the list does.
public partial class Form3 : Form
{
// This button causes the value of a list element to be changed.
private Button changeItemBtn = new Button();
// This DataGridView control displays the contents of the list.
private DataGridView customersDataGridView = new DataGridView();
// This BindingSource binds the list to the DataGridView control.
private BindingSource customersBindingSource = new BindingSource();
public Form3()
{
InitializeComponent();
// Set up the "Change Item" button.
this.changeItemBtn.Text = "Change Item";
this.changeItemBtn.Dock = DockStyle.Bottom;
this.changeItemBtn.Height = 100;
//this.changeItemBtn.Click +=
// new EventHandler(changeItemBtn_Click);
this.Controls.Add(this.changeItemBtn);
// Set up the DataGridView.
customersDataGridView.Dock = DockStyle.Top;
this.Controls.Add(customersDataGridView);
this.Size = new Size(400, 200);
}
private void Form3_Load(object sender, EventArgs e)
{
this.Top = 100;
this.Left = 100;
this.Height = 600;
this.Width = 1000;
// Create and populate the list of DemoCustomer objects
// which will supply data to the DataGridView.
BindingList<DemoCustomer1> customerList = new ();
customerList.Add(DemoCustomer1.CreateNewCustomer());
customerList.Add(DemoCustomer1.CreateNewCustomer());
customerList.Add(DemoCustomer1.CreateNewCustomer());
// Bind the list to the BindingSource.
this.customersBindingSource.DataSource = customerList;
// Attach the BindingSource to the DataGridView.
this.customersDataGridView.DataSource =
this.customersBindingSource;
}
// Change the value of the CompanyName property for the first
// item in the list when the "Change Item" button is clicked.
void changeItemBtn_Click(object sender, EventArgs e)
{
// Get a reference to the list from the BindingSource.
BindingList<DemoCustomer1>? customerList =
this.customersBindingSource.DataSource as BindingList<DemoCustomer1>;
// Change the value of the CompanyName property for the
// first item in the list.
customerList[0].CustomerName = "Tailspin Toys";
customerList[0].PhoneNumber = "(708)555-0150";
}
}
// This is a simple customer class that
// implements the IPropertyChange interface.
public class DemoCustomer1 : INotifyPropertyChanged
{
// These fields hold the values for the public properties.
private Guid idValue = Guid.NewGuid();
private string customerNameValue = String.Empty;
private string phoneNumberValue = String.Empty;
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// The constructor is private to enforce the factory pattern.
private DemoCustomer1()
{
customerNameValue = "Customer";
phoneNumberValue = "(312)555-0100";
}
// This is the public factory method.
public static DemoCustomer1 CreateNewCustomer()
{
return new DemoCustomer1();
}
// This property represents an ID, suitable
// for use as a primary key in a database.
public Guid ID
{
get
{
return this.idValue;
}
}
public string CustomerName
{
get
{
return this.customerNameValue;
}
set
{
if (value != this.customerNameValue)
{
this.customerNameValue = value;
NotifyPropertyChanged();
}
}
}
public string PhoneNumber
{
get
{
return this.phoneNumberValue;
}
set
{
if (value != this.phoneNumberValue)
{
this.phoneNumberValue = value;
NotifyPropertyChanged();
}
}
}
}
}
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Runtime.CompilerServices
Imports System.Windows.Forms
' This form demonstrates using a BindingSource to bind
' a list to a DataGridView control. The list does not
' raise change notifications. However the DemoCustomer1 type
' in the list does.
Public Class Form3
Inherits System.Windows.Forms.Form
' This button causes the value of a list element to be changed.
Private changeItemBtn As New Button()
' This DataGridView control displays the contents of the list.
Private customersDataGridView As New DataGridView()
' This BindingSource binds the list to the DataGridView control.
Private customersBindingSource As New BindingSource()
Public Sub New()
InitializeComponent()
' Set up the "Change Item" button.
Me.changeItemBtn.Text = "Change Item"
Me.changeItemBtn.Dock = DockStyle.Bottom
Me.changeItemBtn.Size = New System.Drawing.Size(100, 100)
AddHandler Me.changeItemBtn.Click, AddressOf changeItemBtn_Click
Me.Controls.Add(Me.changeItemBtn)
' Set up the DataGridView.
customersDataGridView.Dock = DockStyle.Top
Me.Controls.Add(customersDataGridView)
Me.Size = New Size(400, 200)
End Sub
Private Sub Form3_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Me.Load
Me.Top = 100
Me.Left = 100
Me.Height = 600
Me.Width = 1000
' Create and populate the list of DemoCustomer1 objects
' which will supply data to the DataGridView.
Dim customerList As New BindingList(Of DemoCustomer1)
customerList.Add(DemoCustomer1.CreateNewCustomer())
customerList.Add(DemoCustomer1.CreateNewCustomer())
customerList.Add(DemoCustomer1.CreateNewCustomer())
' Bind the list to the BindingSource.
Me.customersBindingSource.DataSource = customerList
' Attach the BindingSource to the DataGridView.
Me.customersDataGridView.DataSource = Me.customersBindingSource
End Sub
' This event handler changes the value of the CompanyName
' property for the first item in the list.
Private Sub changeItemBtn_Click(ByVal sender As Object, ByVal e As EventArgs)
' Get a reference to the list from the BindingSource.
Dim customerList As BindingList(Of DemoCustomer1) =
CType(customersBindingSource.DataSource, BindingList(Of DemoCustomer1))
' Change the value of the CompanyName property for the
' first item in the list.
customerList(0).CustomerName = "Tailspin Toys"
customerList(0).PhoneNumber = "(708)555-0150"
End Sub
End Class
' This class implements a simple customer type
' that implements the IPropertyChange interface.
Public Class DemoCustomer1
Implements INotifyPropertyChanged
' These fields hold the values for the public properties.
Private idValue As Guid = Guid.NewGuid()
Private customerNameValue As String = String.Empty
Private phoneNumberValue As String = String.Empty
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
' This method is called by the Set accessor of each property.
' The CallerMemberName attribute that is applied to the optional propertyName
' parameter causes the property name of the caller to be substituted as an argument.
Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
' The constructor is private to enforce the factory pattern.
Private Sub New()
customerNameValue = "Customer"
phoneNumberValue = "(312)555-0100"
End Sub
' This is the public factory method.
Public Shared Function CreateNewCustomer() As DemoCustomer1
Return New DemoCustomer1()
End Function
' This property represents an ID, suitable
' for use as a primary key in a database.
Public ReadOnly Property ID() As Guid
Get
Return Me.idValue
End Get
End Property
Public Property CustomerName() As String
Get
Return Me.customerNameValue
End Get
Set(ByVal value As String)
If Not (value = customerNameValue) Then
Me.customerNameValue = value
NotifyPropertyChanged()
End If
End Set
End Property
Public Property PhoneNumber() As String
Get
Return Me.phoneNumberValue
End Get
Set(ByVal value As String)
If Not (value = phoneNumberValue) Then
Me.phoneNumberValue = value
NotifyPropertyChanged()
End If
End Set
End Property
End Class
バインドを同期する
Windows フォームでのデータ バインディングの実装時に、複数のコントロールが同じデータ ソースにバインドされます。 場合によっては、コントロールのバインドされたプロパティが互いおよびデータ ソースと確実に同期されるように、追加の手順を実行する必要がある場合があります。 これらの手順は、次の 2 つの状況で必要です。
データ ソースが IBindingListを実装していないため、ListChanged型 ItemChanged イベントを生成する場合。
データ ソースが IEditableObjectを実装している場合。
前者の場合は、BindingSource を使用してデータ ソースをコントロールにバインドできます。 後者の場合は、BindingSource
を使用して BindingComplete イベントを処理し、関連付けられている EndCurrentEditに対して BindingManagerBase を呼び出します。
この概念の実装の詳細については、BindingComplete API リファレンス ページを参照してください。
こちらも参照ください
.NET Desktop feedback