22.2.2 数据绑定对象
图22-14显示了数据绑定中使用的对象的类层次结构。本节将讨论System.Windows.Forms 命名空间中的类BindingContext、CurrencyManager和PropertyManager,说明在把数据绑定到窗体上的一个或多个控件上时,它们是如何交互的。带阴影的对象就是在绑定中使用的对象。
在前面的示例中,我们使用TextBox控件的DataBindings属性把DataSet的一列绑定到控件的Text属性上,DataBindings属性是图22-14所示的ControlsBindingsCollection的一个实例。

图 22-14
textBox1.DataBindings.Add("Text", ds, "Products.ProductName");
这行代码给ControlBindingsCollection添加一个Binding对象。
1. BindingContext
每个Windows窗体都有BindingContext属性,实际上,Form派生于Control,该属性是在Control中定义的,所以大多数控件都有这个属性。BindingContext对象有一个BindingManagerBase实例集合,如图22-15所示。在对控件进行数据绑定时,就会创建这些实例,并把它们添加到绑定管理器对象中。
图 22-15
BindingContext可以包含几个数据源,包装在CurrencyManager或PropertyManager中。使用哪个类取决于数据源本身。
如果数据源包含一个项目列表,例如DataTable、DataView或实现IList接口的对象,就使用CurrencyManager,因为它可以在该数据源中保存当前位置。如果数据源只返回一个值,就把PropertyManager存储在BindingContext中。
只为给定的数据源创建一次CurrencyManager或PropertyManager。如果把两个文本框绑定到DataTable的一个行上,则在BindingContext中只创建一个CurrencyManager。
添加到窗体中的每个控件都链接到窗体的绑定管理器上,因此所有的控件都共享相同的实例。在最初创建一个控件时,其BindingContext属性为空。在把控件添加到窗体的Controls集合中时,就把BindingContext设置为该窗体的Controls集合。
要把控件绑定到一个列上,需要给其DataBindings属性添加一个入口,这是ControlBindingsCollection的一个实例。下面的代码可以创建一个新绑定:
textBox1.DataBindings.Add("Text", ds, "Products.ProductName");
ControlBindingsCollection的Add()方法会从传递给它的参数中创建Binding对象的一个实例,并把它添加到绑定集合中,如图22-16所示。
图22-16显示了把一个Binding添加到控件中的情况。绑定把控件链接到数据源上,存储在Form(或控件本身)的BindingContext中。数据源内部的改变会反映到控件上,控件中的改变也会反映到数据源上。
2. Binding类
这个类把控件的一个属性链接到数据源的一个成员上。在改变该成员时,控件的属性会更新,以反映这个改变。反之亦然,如果文本框中的文本被更新,这个改变也会反映到数据源上。

图 22-16
3. CurrencyManager和PropertyManager
在创建Binding对象时,如果这是第一次绑定数据源中的数据,就会创建对应的CurrencyManager 或 PropertyManager对象。这个类的作用是定义当前记录在数据源中的位置,在改变当前的记录时,需要调整所有的ListBindings。图22-17显示了Products表中的两个字段,包含一种通过跟踪栏控件在记录之间移动的方式。

图 22-17
ScrollingDataBinding示例的代码如下所示:
using System;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
public class ScrollingDataBinding : System.Windows.Forms.Form
{
private Button retrieveButton;
private TextBox textName;
private TextBox textQuan;
private TrackBar trackBar;
private DataSet ds;
应用程序在ScrollingDataBinding构造函数中创建窗口以及该窗口中的所有控件:
public ScrollingDataBinding()
{
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(464, 253);
this.Text = "09_ScrollingDataBinding";
this.retrieveButton = new Button();
retrieveButton.Location = new System.Drawing.Point(4, 4);
retrieveButton.Size = new System.Drawing.Size(75, 23);
retrieveButton.TabIndex = 1;
retrieveButton.Anchor = AnchorStyles.Top | AnchorStyles.Left;
retrieveButton.Text = "Retrieve";
retrieveButton.Click += new System.EventHandler
(this.retrieveButton_Click);
this.Controls.Add(this.retrieveButton);
this.textName = new TextBox();
textName.Location = new System.Drawing.Point(4, 31);
textName.Text = "Please click retrieve...";
textName.TabIndex = 2;
textName.Anchor = AnchorStyles.Top | AnchorStyles.Left |
AnchorStyles.Right ;
textName.Size = new System.Drawing.Size(456, 20);
textName.Enabled = false;
this.Controls.Add(this.textName);
this.textQuan = new TextBox();
textQuan.Location = new System.Drawing.Point(4, 55);
textQuan.Text = "";
textQuan.TabIndex = 3;
textQuan.Anchor = AnchorStyles.Top | AnchorStyles.Left |
AnchorStyles.Top;
textQuan.Size = new System.Drawing.Size(456, 20);
textQuan.Enabled = false;
this.Controls.Add(this.textQuan);
this.trackBar = new TrackBar();
trackBar.BeginInit();
trackBar.Dock = DockStyle.Bottom ;
trackBar.Location = new System.Drawing.Point(0, 275);
trackBar.TabIndex = 4;
trackBar.Size = new System.Drawing.Size(504, 42);
trackBar.Scroll += new System.EventHandler(this.trackBar_Scroll);
trackBar.Enabled = false;
this.Controls.Add(this.trackBar);
}
单击Retrieve按钮后,事件处理程序就会从Products表中选择所有的记录,并把它们保存到私有数据集ds中:
protected void retrieveButton_Click(object sender, System.EventArgs e)
{
retrieveButton.Enabled = false ;
ds = CreateDataSet();
接着,绑定两个文本控件:
textName.DataBindings.Add("Text" , ds ,
"Products.ProductName");
textQuan.DataBindings.Add("Text" , ds ,
"Products.QuantityPerUnit");
trackBar.Minimum = 0 ;
trackBar.Maximum = this.BindingContext[ds,"Products"].Count --1;
textName.Enabled = true;
textQuan.Enabled = true;
trackBar.Enabled = true;
}
这里有一个记录滚动机制,该机制响应TrackBar小图标的移动:
protected void trackBar_Scroll(object sender , System.EventArgs e)
{
this.BindingContext[ds,"Products"].Position = trackBar.Value;
}
private DataSet CreateDataSet()
{
string source = "server=(local)\\NetSDK;" +
"uid=QSUser;pwd=QSPassword;" +
"database=northwind";
string customers = "SELECT * FROM Products";
SqlConnection con = new SqlConnection(source);
SqlDataAdapter da = new SqlDataAdapter(customers , con);
DataSet ds = new DataSet();
da.Fill(ds , "Products");
return ds;
}
static void Main()
{
Application.Run(new ScrollingDataBinding());
}
}
在开始检索数据时,跟踪栏的最大位置就设置为记录的个数。接着在上面的滚动方法中,把Products数据表中BindingContext的位置设置为滚动条的位置,这样就可以有效地改变DataTable中的当前记录,绑定到当前行上的所有控件(在本例中是两个文本框)就会被更新。
本节介绍了如何绑定到各种数据源上,例如数组、数据表、数据视图和各种其他数据容器,如何排序和过滤数据。22.3节将讨论如何扩展Visual Studio,以允许进行数据访问,得到与应用程序的更好集成。






