[ASP.NET 控制項實作 Day22] 讓 DropDownList 不再因項目清單不存在而造成錯誤

DropDownList 控制項常常會因為項目清單中不存在繫結的欄位,而發生以下的錯誤訊息。因為繫結資料的不完整或異常就會造成這樣的異常錯誤,在設計上實在是相當困擾,而且最麻煩的是這個錯誤在頁面的程式碼也無法使用 Try ... Catch 方式來略過錯誤。其實最簡單的方式就去直接去修改 DropDownList 控制項,讓 DropDownList 控制項繫結資料時,就算欄位值不存在清單項目中也不要釋出錯誤,本文就要說明如何繼承 DorpDownList 下來修改,來有效解決這個問題。

DropDownList 控制項常常會因為項目清單中不存在繫結的欄位,而發生以下的錯誤訊息。因為繫結資料的不完整或異常就會造成這樣的異常錯誤,在設計上實在是相當困擾,而且最麻煩的是這個錯誤在頁面的程式碼也無法使用 Try ... Catch 方式來略過錯誤。其實最簡單的方式就去直接去修改 DropDownList 控制項,讓 DropDownList 控制項繫結資料時,就算欄位值不存在清單項目中也不要釋出錯誤,本文就要說明如何繼承 DorpDownList 下來修改,來有效解決這個問題。

image

程式碼下載:ASP.NET Server Control - Day22.rar
Northwnd 資料庫下載:NORTHWND.rar

 

一、覆寫 SelectedValue 屬性解決資料繫結的問題

DropDownList 控制項繫結錯誤的原因,可以由上圖的錯誤訊息可以大概得知是寫入 SelectedValue 屬性時發生的錯誤;所以我們繼承 DorpDownList 下來命名為 TBDropDownList,並覆寫 SelectedValue 屬性來解決這個問題。解決方式是在寫入 SelectedValue 屬性時,先判斷準備寫入的值是否存在項目清單中,存在的話才寫入 SelectedValue 屬性,若不存在則直接設定 SelectedIndex 屬性為 -1。

 


    Public Class TBDropDownList
        Inherits DropDownList

        ''' <summary>
        ''' 覆寫 SelectedValue 屬性。
        ''' </summary>
        Public Overrides Property SelectedValue() As String
            Get
                Return MyBase.SelectedValue
            End Get
            Set(ByVal value As String)
                Dim oItem As ListItem = Me.Items.FindByValue(value)
                If (oItem Is Nothing) Then
                    Me.SelectedIndex = -1 '當 Items 不存在時 
                    Exit Property
                Else
                    MyBase.SelectedValue = value
                End If
            End Set
        End Property

    End Class

我們以 Northwnd 資料庫的 Products 資料表做為測試資料,事先定義 DropDownList 的 Items 內容,其中第一個加入 "未對應" 的項目,將 SelectedValue 屬性繫結至 CategoryID 欄位。

 


                <bee:TBDropDownList ID="DropDownList1" runat="server" 
                    SelectedValue='<%# Bind("CategoryID") %>'>
                    <asp:ListItem Value="">未對應</asp:ListItem>
                    <asp:ListItem Value="2">Condiments</asp:ListItem>
                    <asp:ListItem Value="3">Confections</asp:ListItem>
                </bee:TBDropDownList>

當資料的 CategoryID 欄位值不存在於 DropDownList 的 Items 集合屬性中時,就會顯示第一個 "未對應" 的項目。

image

 

二、TBDropDownList 設定 DataSoruceID 產生的問題

上述的解決方法在筆者的「讓 DropDownList DataBind 不再發生錯誤」一文中已經有提及,不過有讀者發現另一個問題,就是當 DropDownList 設定 DataSourceID 時卻會發生資料無法正常繫結,以下就來解決這個問題。

我們設定 TBDropDownList 的 DataSoruceID 來取得項目清單的內容,將 DataSourceID 設定為另一個取得 Categories 資料表內容的 SqlDataSource 控制項。

 


                <bee:TBDropDownList ID="DropDownList1" runat="server" 
                    SelectedValue='<%# Bind("CategoryID") %>' DataSourceID="SqlDataSource2" 
                    DataTextField="CategoryName" DataValueField="CategoryID">
                </bee:TBDropDownList>
                <asp:SqlDataSource ID="SqlDataSource2" runat="server" 
                    ConnectionString="<%$ ConnectionStrings:Northwnd %>" 
                    SelectCommand="SELECT CategoryID, CategoryName, Description, Picture FROM Categories" 
                    ProviderName="<%$ ConnectionStrings:Northwnd.ProviderName %>" >
                </asp:SqlDataSource>

當執行程式時,FormView 原本在瀏覽模式時的 CategoryID 欄位值為 7 (CategoryName 應為 Product)。

image

image

當按下「編輯」時切換到 EditItemTemplate 時,改用 TBDropDownList 繫結 CategoryID 欄位值,可以這時欲無法繫結正確的值。

image

 

三、解決 TBDropDownList 設定 DataSourceID 造成資料無法繫結的問題

要解決上述 TBDropDownList 設定 DataSourceID 問題,需在設定 SelectedValue 屬性時,若 Items.Count=0 先用一個 FCachedSelectedValue 變數將正確的值先暫存下來,然後覆寫 PerformDataBinding 方法,當 DorpDownList 取得 DataSoruceID 所對應的項目清單內容後,因為這時 Items 的內容才會完整取回,再去設定一次 SelectedValue 屬性就可以正確的繫結資料。

 


    Public Class TBDropDownList
        Inherits DropDownList

        Private FCachedSelectedValue As String

        ''' <summary>
        ''' 覆寫 SelectedValue 屬性。
        ''' </summary>
        Public Overrides Property SelectedValue() As String
            Get
                Return MyBase.SelectedValue
            End Get
            Set(ByVal value As String)
                If Me.Items.Count <> 0 Then
                    Dim oItem As ListItem = Me.Items.FindByValue(value)
                    If (oItem Is Nothing) Then
                        Me.SelectedIndex = -1 '當 Items 不存在時 
                    Else
                        MyBase.SelectedValue = value
                    End If
                Else
                    FCachedSelectedValue = value
                End If
            End Set
        End Property

        Protected Overrides Sub PerformDataBinding(ByVal data As System.Collections.IEnumerable)
            MyBase.PerformDataBinding(data)

            'DataSoruceID 資料繫結後再設定 SelectedValue 屬性值
            If (Not FCachedSelectedValue Is Nothing) Then
                Me.SelectedValue = FCachedSelectedValue
            End If
        End Sub

    End Class

重新執行程式,切換到編輯模式時,TBDropDownList 就可以正確的繫結欄位值了。

image

 

備註:本文同步發佈於「第一屆iT邦幫忙鐵人賽」,如果你覺得這篇文章對您有幫助,記得連上去推鑒此文增加人氣 ^^
http://ithelp.ithome.com.tw/question/10012909
http://ithelp.ithome.com.tw/question/10012915

ASP.NET 魔法學院