这两天在看一个程序,这个程序其实很简单,就是装载数据,然后添加数据绑定,然后通过修改BindingManageBase的Positon属性,来进行记录的导航,这是一个.net 1.1的程序,在Ado.net2.0中,一般我们是通过BindingSource类做数据绑定,然后通过BindingNavigator类做自动导航,下面是源程序:
Dim comm As New SqlCommand
Dim SqlDa As SqlDataAdapter
Dim SqlDs As New DataSet
Dim bmData As BindingManagerBase
在窗体的Load事件中加载数据:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
SqlDa = New SqlDataAdapter("Select 学号,姓名,性别,班级编号 From 学生信息", conn)
SqlDa.Fill(SqlDs, "学生信息")
SqlDa.SelectCommand.CommandText = "Select Distinct 班级编号,班级名称 From 班级"
SqlDa.Fill(SqlDs, "班级")
' 取得代表 "学生信息" 数据表的 CurrencyManager 对象
bmData = Me.BindingContext(SqlDs, "学生信息")
'*************************
ComboBox1.DataSource = SqlDs.Tables("学生信息")
ComboBox1.DisplayMember = "学号"
ComboBox1.SelectedIndex = 0
'*************************
'TextBox1.DataBindings.Add("Text", SqlDs, "学生信息.姓名")
TextBox1.DataBindings.Add("Text", SqlDs.Tables("学生信息"), "姓名")
'*************************
Dim SexArray() As String = {"男", "女"}
ComboBox2.DataSource = SexArray
ComboBox2.DataBindings.Add("Text", SqlDs, "学生信息.性别")
'*************************
' 将ComboBox控件的数据源设定成数据集SqlDs1内的班级数据表
ComboBox3.DataSource = SqlDs.Tables("班级")
' 将ComboBox控件的DisplayMember属性设定成班级数据表的班级名称字段
ComboBox3.DisplayMember = "班级名称"
' 将ComboBox控件的ValueMember属性设定成班级数据表的班级编号字段
ComboBox3.ValueMember = "班级编号"
ComboBox3.DataBindings.Add("SelectedValue", SqlDs, "学生信息.班级编号")
'*************************
DataGrid1.DataSource = SqlDs.Tables("学生信息")
DataGrid1.CaptionText = "浏览" & ComboBox3.Text & "班的学生信息"
End Sub
然后在窗体上画几个按钮,分别实现“首记录”、“上一条”、“下一条”、“最后一条”的导航功能,这些功能都是通过改变bmData.Position属性来实现的,在MSDN文档和书上,我们可以看到,对于数据绑定的这句代码:
TextBox1.DataBindings.Add("Text", SqlDs.Tables("学生信息"), "姓名")
添加绑定的Add方法有三个参数,第一个参数是指定要将控件的哪个属性与数据库表字段进行绑定,第二个参数是数据源,可以是DataSet,也可以是Table,如果是DataSet,则第三个参数的格式为“TableName.FiledName”,如果是Table,则第三个参数直接填写表中的字段名即可。
按照这样的说法,下面两个绑定都应该是正确的:
'TextBox1.DataBindings.Add("Text", SqlDs, "学生信息.姓名")
TextBox1.DataBindings.Add("Text", SqlDs.Tables("学生信息"), "姓名")
但实际上被注释的第一句能够使程序正常运行,第二种绑定方式,我们通过修改bmData.Position属性,并不能使的绑定文本框中的内容显示为bmData.Position属性指向的那条数据纪录,这是为什么?百思不得其解,在博客园的博问和CSDN论坛中都发帖请教高手,没有得到回应,只好自己去想,竟也找到了问题的原因:
bmData = Me.BindingContext(SqlDs, "学生信息")
这句代码是通过窗体的BindingContext方法返回一个CurrencyManager对象,然后赋值给BindingManageBase对象,BindingManageBase是一个抽象类,MSDN的说明是:“管理绑定到相同数据源和数据成员的所有 Binding 对象。该类为抽象类。”既然两种绑定方式都是正确的,那么问题的原因应该不会出在绑定的语句上,于是我查了Form类的属性BindingContext的说明,发现这个属性有多个重载版本:
于是我试着将这行代码:
bmData = Me.BindingContext(SqlDs, "学生信息")
修改为:
bmData = Me.BindingContext(SqlDs.Tables("学生信息"))
发现这么一改,用下面的绑定方式就能正常工作了:
TextBox1.DataBindings.Add("Text", SqlDs.Tables("学生信息"), "姓名")
从BindingContext的属性说明来看,它是用于获取与指定数据源关联的BindingManageBase对象,如果我们获取时没有改对象,则会创建一个,在获取时可以通过指定数据源,或者指定数据源和数据成员的方式,指定的方式决定了,后续绑定时,采用的是下述哪种方法:
- TextBox1.DataBindings.Add("Text", SqlDs, "学生信息.姓名"),如果绑定时,指定的是DataSet和数据表成员,则必须采用这种控件绑定方式
- TextBox1.DataBindings.Add("Text", SqlDs.Tables("学生信息"), "姓名"),如果绑定时,指定的数据源是数据表,则必须采用这种控件绑定方式
这就是为什么程序中两种绑定方式只有一种能正常工作的原因了。