上篇中我们实作了 GridView 的 TBDropDownField 字段类别,不过眼尖的读者不知有没有发觉我们并处理 Items 属性取得成员清单的动作,而是直接设定储存格内含的 TBDropDownList 控件相关属性 (DataSourceID、DataTextField、DataValueField 属性) 后,就由 TDropDownList 控件自行处理 Items 属性的数据系结。当 GridView 的资料列是编辑状态时,下拉列表会显示出 Items 的文字内容;可是浏览状态的数据列,却是显示字段原始值,无法呈现 Items 的文字内容。本文将说明如何自行处理 TBDropDownField 的 Items 属性的数据系结动作,并使只读状态的数据列也可以呈现 Items 的文字内容。

image

程序代码下载:ASP.NET Server Control - Day24.rar
Northwnd 数据库下载:NORTHWND.rar

 

一、Items 属性的问题

我们重新看一次原本 TBDropDownField 类别在处理 Items 属性的数据系结取得清单内容的程序代码,在覆写 InitializeDataCell 方法中,当储存格为编辑模式时,会呈现 TBDropDownList 控件并设定取得 Items 清单内容的相关属性,让 TBDropDownList 自行去处理它的 Items 属性的清单内容。

                        '由資料來源控制項取得清單項目
                        oDropDownList.DataSourceID = Me.DataSourceID
                        oDropDownList.DataTextField = Me.DataTextField
                        oDropDownList.DataValueField = Me.DataValueField

 

不知你有没有发觉,我们无论在 InitializeDataCell 及 OnDataBindField 方法中,都没有针对 TBDropDownList 控件做任何 DataBind 动作,那它是怎么从 DataSourceID 关联的数据来源撷取数据呢?因为 GridView 在执行 DataBind 时,就会要求所有的子控件做 DataBind,所以我们只要设定好 TBDropDownList 控件相关属性后,当 TBDropDownList 自动被要求数据系结时就会取得 Items 的清单内容。

当然使用 TBDropDownList 控件去处理 Items 的数据系结动作最简单,可是这样只读的储存格只能显示原始字段值,无法呈现 Items 中对应成员的文字;除非无论只读或编辑状态,都要建立 TBDropDownList 控件去取得 Items 清单内容,而只读字段使用 TBDropDownList.Items 去找到对应成员的显示文字,不过这样的作法会怪怪的,而且没有执行效能率。所以比较好的辨法,就是由 TBDropDownField 类别自行处理 Items 的资料系结,同时提供给只读状态的 DataControlFieldCell 及编辑状态的 TBDropDownList 使用。

 

二、由 TBDropDownField 类别处理 Items 属性的数据系结

我们要自行处理 Items 属性来取得成员清单,在 InitializeDataCell 方法中无须处理 Items 属性,只需产生储存格需要的子控件,未来在执行子控件的 DataBinding 时的 OnDataBindField 方法中再来处理 Items 属性。

        Protected Overrides Sub InitializeDataCell( _
            ByVal Cell As DataControlFieldCell, _
            ByVal RowState As DataControlRowState)
 
            Dim oDropDownList As TBDropDownList
            Dim oControl As Control
 
            If Me.CellIsEdit(RowState) Then
                oDropDownList = New TBDropDownList()
                oControl = oDropDownList
                Cell.Controls.Add(oControl)
            Else
                oControl = Cell
            End If
 
            If (oControl IsNot Nothing) AndAlso MyBase.Visible Then
                AddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)
            End If
        End Sub

 

在 OnDataBindField 方法中,我们加上一段处理 Items 属性的程序代码如下,会利用 PerformSelecrt 私有方法,由关联的数据来源 (即 DataSrouceID 指定的数据来源控件) 撷取数据并产生 Items 的成员清单,在后面会详细讲解 PerformSelecrt 方法处理撷取数据的细节。因为 TBDropDownField 每个数据储存格都会执行 OnDataBindField 方法,但 Items 取得成员清单的动作只需做一次即可,所以会以 FIsPerformSelect 区域变量来判断是否已取得 Items 的成员清单,若已取过就不重新取得,这样比较有执行效能。

            If Not Me.DesignMode Then
                If Not FIsPerformSelect Then
                    '從關聯的資料來源擷取資料
                    PerformSelect()
                    FIsPerformSelect = True
                End If
            End If

 

当取得储存储的对应的字段值时,依此字段值由 Items 集合去取得对应的 ListItem 成员,并以此 ListItem.Text 的文字内容来做显示。

            '由 Items 去取得對應成員的顯示內容
            oListItem = Me.Items.FindByValue(CCStr(sText))
            If oListItem IsNot Nothing Then
                sText = oListItem.Text
            End If

 

若是由 TBDropDownList 所引发的 OnDataBindField 方法时,使用 SetItems 私有方法将 TBDropDownField.Items 属性复制给 TBDropDownList.Item 属性。

                ODropDownList = DirectCast(oControl, TBDropDownList)
                SetItems(ODropDownList)

 

SetItems 私有方法的程序代码如下。

        Private Sub SetItems(ByVal DropDownList As TBDropDownList)
            Dim oItems() As ListItem
 
            If Not Me.DesignMode Then
                ReDim oItems(Me.Items.Count - 1)
                Me.Items.CopyTo(oItems, 0)
                DropDownList.Items.AddRange(oItems)
            End If
        End Sub

 

三、由关连的数据来源撷取数据

再来就是重点就是要处理 PerformSelecrt 私有方法,来取得 Items 属性的成员清单内容。PerformSelect 方法的作用是去寻找页面上的具 IDataSource 接口的控件,并执行此数据来源的 Select 方法,以取得数据来设定 Items 的清单内容。

step1. 寻找数据来源控件
PerformSelect 方法中有使用 FindControlEx 方法,它是自订援寻控件的多载方法,是取代 FindControl 进阶方法。程序代码中使用 FindControlEx 去是页面中以递归方式寻找具有 IDataSource 接口的控件,且 ID 属性值为 TBDropDownList.ID 的属性值。

step2. 执行数据来源控件的 Select 方法

当找到数据来源控件后 (如 SqlDataSource、ObjectDataSource ...等等),执行其 DataSourceView.Select 方法,此方法需入一个 DataSourceViewSelectCallback 函式当作参数,当数据来源控件取得数据后回呼我们指定的 OnDataSourceViewSelectCallback 函式中做后序处理。

step3. 将取得的数据来设定生 Items 的清单内容

在 OnDataSourceViewSelectCallback 函式中接到回传的具 IEnumerable 接口的数据,有可能是 DataView、DataTable ...等型别的资料。利用 DataBinder.GetPropertyValue 来取得 DataTextField 及 DataValueField 设定的字段值,逐一建立 ListItem 项目,并加入 Items 集合属性中。

        ''' <summary>
        ''' 從關聯的資料來源擷取資料。
        ''' </summary>
        Private Sub PerformSelect()
            Dim oControl As Control
            Dim oDataSource As IDataSource
            Dim oDataSourceView As DataSourceView
 
            '若未設定 DataSourceID 屬性則離開
            If StrIsEmpty(Me.DataSourceID) Then Exit Sub
            '找到具 IDataSource 介面的控制項
            oControl = FindControlEx(Me.Control.Page, GetType(IDataSource), "ID", Me.DataSourceID)
            If oControl Is Nothing Then Exit Sub
 
            oDataSource = DirectCast(oControl, IDataSource)
            oDataSourceView = oDataSource.GetView(String.Empty)
            oDataSourceView.Select(DataSourceSelectArguments.Empty, _
                        New DataSourceViewSelectCallback(AddressOf Me.OnDataSourceViewSelectCallback))
        End Sub
 
        ''' <summary>
        ''' 擷取資料的回呼函式。
        ''' </summary>
        ''' <param name="data">取得的資料。</param>
        Private Sub OnDataSourceViewSelectCallback(ByVal data As IEnumerable)
            Dim oCollection As ICollection
            Dim oValue As Object
            Dim oItem As ListItem
 
            Me.Items.Clear()
            If data Is Nothing Then Exit Sub
 
            oCollection = TryCast(data, ICollection)
            Me.Items.Capacity = oCollection.Count
 
            For Each oValue In data
                oItem = New ListItem()
                If StrIsNotEmpty(Me.DataTextField) Then
                    oItem.Text = DataBinder.GetPropertyValue(oValue, DataTextField, Nothing)
                End If
                If StrIsNotEmpty(Me.DataValueField) Then
                    oItem.Value = DataBinder.GetPropertyValue(oValue, DataValueField, Nothing)
                End If
                Me.Items.Add(oItem)
            Next
        End Sub

 

四、测试程序

使用上篇中同一个案例做测试,同样以 Northwnd 数据库的 Products 数据表为例。在 GridView 加入自订的 TBDropDownField 字段系结 CategoryID 字段,并设定 DataSourceID、DataTextField、DataValueField 属性;另外加入另一个 BoundField 的只读字段,也同样系结 CategoryID 字段来做比较。

                <bee:TBDropDownField  HeaderText="CategoryID"  
                    SortExpression="CategoryID" DataField="CategoryID" 
                    DataTextField="CategoryName" DataValueField="CategoryID" DataSourceID="SqlDataSource2">
                </bee:TBDropDownField>
                <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" 
                    SortExpression="CategoryID"  ReadOnly="true" />

 

执行程序,在 GridView 浏览的模式时,TBDropDownField 的储存格已经会呈现 Items 对应成员的显示文字。

image

 

执行数据列编辑时,也可以正常显示下拉列表的内容。

image

 

备注:本文同步发布于「第一届iT邦帮忙铁人赛」,如果你觉得这篇文章对您有帮助,记得连上去推鉴此文增加人气 ^^
http://ithelp.ithome.com.tw/question/10013041
http://ithelp.ithome.com.tw/question/10013047

posted on 2008-10-25 18:38  jeff377  阅读(1595)  评论(4编辑  收藏  举报