ADO.NET的数据绑定机制剖析及其应用

    当在程序中需要显示多条记录时,我们往往希望能给记录一个“记录号”以方便定位记录,比如:“到第一条”,“到最后一条”,“跳到第100条”……。

    DataTable中的记录(即DataRow)本身并没有一个所谓的“记录号”,DataTable本身也没有提供这种功能。

    提示:

    在VB6中,记录集对象RecordSet提供MoveFirst,MoveLast等定位功能。这是由ADO实现的。在ADO.NET中,DataTable和DataRow都没有这些方法。

 

    乍看起来,不能在数据集中移动,好象是ADO.NET设计的一个疏漏。事实上,ADO.NET把所有在数据集中定位的功能全部抽取出来,再加上其他一些功能,构建了ADO.NET的数据绑定机制,与原来ADO所提供的有限定位功能相比,ADO.NET更为强大而灵活。

    请试着运行本书配套光盘中的示例MoveInDataTable,其运行界面如715



715
数据绑定示例

 

    这个程序在运行时,既可以点击右下方的四个按钮,也可以直接点击上部的网格在数据集中移动,当前行的内容同步在下半部的两个文本框中显示。可以在文本框中直接修改数据,当移动到其它行时,网格中的记录同步刷新。

    通过这个示例,我们来剖析ADO.NET中数据绑定机制的原理。

1 什么叫数据绑定?

    所谓数据绑定,通俗地说,就是把数据源(如DataTable)中的数据取出来,显示在窗体的各种控件上,用户可以通过这些控件查看和修改数据,这些修改会自动地保存到数据源中,参见716

 


716
数据绑定原理

 

    Windows 窗体可以利用两种类型的数据绑定:简单绑定和复杂绑定。这两种类型具有不同的优点。

l         简单绑定

    简单数据绑定指将一个控件绑定到单个数据元素(如数据集表的列中的值)的能力。这是用于 TextBox 控件或 Label 控件等控件(即通常只显示单个值的控件)的典型绑定类型。 715中的两个文本框,分别绑定到了DataTable中的“AddressStr”和“ClientName”两个字段。

l         复杂绑定

    复杂数据绑定指将一个控件绑定到多个数据元素的能力,通常绑定到数据库中的多条记录。 715中的DataGrid就绑定到了一个DataTable,它可以一次显示多条记录和多个字段的值。

 

2 实现在数据集中移动

    在数据集中移动是数据绑定机制中的一个子功能。

    为了方便理解ADO.NET中复杂的数据绑定机制,我们先在MoveInDataTable示例中的一个简单的窗体内实现数据移动功能,参见717

 


717
手动实现在记录集中移动

下面对代码进行分析

1)程序需要提取数据,Sub过程GetData实现这一功能:

    '定义相关变量

    Private conn As OleDbConnection

    Private comm As OleDbCommand

    Private da As OleDbDataAdapter

    Private ds1 As New DataSet

      

   '获取数据

    Private Sub GetData()

        '创建连接对象连接数据库

        conn = New OleDbConnection

        conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\Clients.mdb;Persist Security Info=False"

        conn.Open()

        '创建命令对象用于向数据库发送SQL命令

        comm = New OleDbCommand

        comm.CommandText = "select * from OrderClient"

        comm.CommandType = CommandType.Text

        comm.Connection = conn

        '创建DataAdapter用于填充DataSet

        da = New OleDbDataAdapter(comm)

        '填充数据

        da.Fill(ds1)

        conn.Close()

    End Sub

 

注意,假设数据库Clients.MDB放在“D:\”下。这些代码我们已经很熟悉了。

2)设定数据绑定,Sub过程SetDataBing()实现这一功能:

 

      '数据绑定管理对象

    Private cm As CurrencyManager

     '设置数据绑定

    Private Sub SetDataBinding()

        '将DataGrid绑定到DataTable

        Me.DataGrid1.DataSource = ds1.Tables(0)

        '获取数据绑定管理对象

        cm = Me.BindingContext(ds1.Tables(0))

    End Sub

    在示例程序的第二窗体(参见715)中,只不过是多了将文本框绑定到DataTable中的字段中的代码:

        Me.txtAddress.DataBindings.Add("Text", ds1.Tables(0), "AddressStr")

        Me.txtName.DataBindings.Add("Text", ds1.Tables(0), "ClientName")

    可以看到,给DataGrid设置数据绑定非常简单,只需直接设定其DataSource属性就行了。

    给文本框设置数据绑定,需要向其DataBindings集合增加一项,其格式为:

         "要绑定的属性名", 被绑定的DataTable对象, "DataTable中的字段名"

    在上面的代码中,控件都是直接绑定到DataTable中的,事实上,也可直接绑定到DataSet,但这时需要对代码做一些改变:

 

        '将DataGrid绑定到DataTable

        Me.DataGrid1.DataSource = ds1

        Me.DataGrid1.DataMember = ds1.Tables(0).TableName

        '绑定文本框

        Me.txtAddress.DataBindings.Add("Text", ds1, ds1.Tables(0).TableName & ".AddressStr")

        Me.txtName.DataBindings.Add("Text", ds1, ds1.Tables(0).TableName & ".ClientName")

 

    因为DataSet中可能会有多个DataTable,所以,必须给DataGrid的DataMember属性指明一个表名。在程序中动态指定某个DataTable表名,就可以动态地将DataGrid与此表名相对应的DataTable绑定。

    文本框绑定的第三个参数被称为“绑定字串”,以英文句点隔开,其格式为:

         表名.字段名

    其特点是越左边的子字串其范围就越大。

 

技术内幕:

     其实数据绑定不仅限于DataSet和DataTable,同样可以将文本框和DataGrid之类绑定到其它对象,如数组和ArrayList,这时,绑定字串就显得非常重要了,有兴趣的读者可以在MSDN中通过搜索“数据绑定”关键字了解如何绑定到非DataSet和DataTable数据。

 

3)现在可以在记录集中移动了,这是通过给CurrencyManager的Position属性赋值实现的,下面列出了关键的代码:

 

     '移到第一条

     cm.Position = 0

 

    '移到前一条

     If cm.Position > 0 Then

            cm.Position -= 1

     End If

  

     '移到下一条

     If cm.Position < cm.Count - 1 Then

            cm.Position += 1

     End If

 

    '移到最后一条

    cm.Position = cm.Count - 1

 

    可以看到,在数据集中移动是通过CurrencyManager对象来实现的。

 

    展示的代码虽然简单,但如果不理解这背后所隐藏的机制,还是无法充分地利用数据绑定机制的。

3 数据绑定原理

ADO.NET的数据绑定机制主要由以下类构成:

 


718
数据绑定类

 

    718以UML图符方式展示了ADO.NET中数据绑定的核心架构(注意,并没有完整地画出所有的类)。

 

提示:

    UML简称为Unified Modeling Language(统一建模语言),它使用图形的方式来表达面向对象的软件系统架构,目前已被软件业广泛接受,成为了国际标准。本书第四部分介绍面向对象编程中就大量地使用UML类图表达程序结构。本书附录中有一个UML基础教程,可供读者参考学习。

   

现在逐个介绍每个类。

    从示例中我们已经知道,象文本框这样的控件都可以绑定到字段上,这一事实本身包含以下信息:

    要绑定的自身属性(如Text属性)

    提供数据来源的对象(如DataTable)

    绑定导航字串

    …………

    这些信息被封装起来,形成了Binding类。每个实现了数据绑定的控件都至少有一个Binding对象,表明它的绑定信息。

    一个窗体上可能会有多个控件(比如多个文本框)绑定到一个数据源,这就意味着存在着多个Binding对象。因此需要有一个类来管理这些对象,这个类就是BindingManagerBase类,但这个类是个抽象类,不能直接创建对象,类CurrencyManager直接继承自BindingManagerBase类,实现了所有基类未实现的功能,可以直接被使用。在数据集中移动的功能就是由 CurrencyManager对象实现的。

    现在知道了,要在数据集中移动,必须想法获取与此数据集对应的CurrencyManager对象。那怎样做到这点?

    一个窗体上不仅会有多个控件(比如多个文本框)绑定到一个数据源,还可能出现多个控件绑定到多个数据源的情况(假设窗体中有两个DataSet,分别为两组控件提供数据,则在窗体中就会存在两个CurrencyManager对象),因此,再设计一个类用于管理这些CurrencyManager对象,这就是BindingContext类的功能。每个其上有数据绑定的窗体对象都至少会有一个BindingContext对象。

    现在小结一下:

    获取窗体的BindingContext对象àBindingContext对象获取CurrencyManager对象à通过CurrencyManager对象以实现在记录集中移动的功能

    这就是实现在数据集中移动功能的技术内幕。

    说了这么多,其实在示例代码中只需要一句就行了:

'数据绑定管理对象

         Private cm As CurrencyManager

         '…………

        '获取数据绑定管理对象

        cm = Me.BindingContext(ds1.Tables(0))

 

 

自我探索:

    一个容器控件比如Form、GroupBox和TabControl都可以有自己的BindingContext对象,以下代码设定了两个GroupBox的BindingContext对象:

    Dim bcG1 As New BindingContext()

    Dim bcG2 As New BindingContext()

      

    groupBox1.BindingContext = bcG1

    groupBox2.BindingContext = bcG2

    请设计一个应用程序,其上有两个GroupBox,每个GroupBox中都有一些数据绑定控件,编程实现这两组控件显示同一数据源中的不同位置的数据。

3 设计数据绑定辅助类

    从前面介绍的内容可以看到,ADO.NET提供的数据绑定功能虽然灵活,但确实过于复杂而不好用了,而在数据集中移动的功能是非常常见的,如果在每一个窗体中都重复这些代码,实在是一件枯燥无聊的工作。因此,可以把这些代码封装起来,作为一个数据绑定辅助类。DataBindingHelper类就是出于这个目的而创建的。

    首先定义一些类的成员变量:

 

'内部绑定管理器

    Private _cm As CurrencyManager = Nothing

    '内部的绑定控件容器,通常是窗体

    Private _container As Control = Nothing

 

    '向外界表露CurrencyManager对象

    Public ReadOnly Property cm() As CurrencyManager

        Get

            Return _cm

        End Get

    End Property

 

    '容器控件

    Public Property container() As Control

        Get

            Return _container

        End Get

        Set(ByVal Value As Control)

            _container = Value

        End Set

    End Property

 

接着需要提供一个方法来指定数据源:

 

'数据源属性,可以指定DataMember(对于DataSet),也可省略,对于DataTable

    Public Sub setDataSource(ByVal datasource As Object, Optional ByVal dataMember As String = Nothing)

 

        If _container Is Nothing Then

            MsgBox("请先指定控件容器")

            Exit Sub

        End If

        If dataMember Is Nothing Then

            _cm = _container.BindingContext(datasource)

        Else

            _cm = _container.BindingContext(datasource, dataMember)

        End If

    End Sub

 

现在就可以实现移动功能了,以后移一条记录为例:

 

     Public Sub MoveNext()

        '_cm未创建或为空,均退出

        If _cm Is Nothing Then

            Exit Sub

        End If

        If _cm.Count = 0 Then

            Exit Sub

        End If

 

        If _cm.Position < _cm.Count - 1 Then

            _cm.Position += 1

        End If

    End Sub

 

有了DataBindingHelper类,实现在数据集中移动就非常简单了,以下是示例工程中的代码:

 

Dim dbh1 As New DataBindingHelper

'设定容器对象为窗体

        dbh1.container = Me

‘设定数据源

        dbh1.setDataSource(ds1.Tables(0))

移动代码如下:

Private Sub btnMoveFirst1_Click(……) Handles btnMoveFirst1.Click

        dbh1.MoveFirst()

    End Sub

 

    Private Sub btnMovePrev_Click(……) Handles btnMovePrev.Click

        dbh1.MovePrev()

    End Sub

 

是不是非常简单?

从这个小示例中相信您一定能体会到面向对象技术所带来的好处!
原文出自:http://blog.csdn.net/bitfan/archive/2005/02/02/278461.aspx

posted @ 2006-12-09 00:10  小淋  阅读(981)  评论(0编辑  收藏  举报