我們在開發 ASP.NET 時,因為大部分資料都是從資料庫中讀取出來的,所以很常見的情況是在用 DropDownList 時,其選項(ListIem)是透過資料庫 DataBinding 過來的,而在建置管理介面的「編輯」頁面時,DropDownList 都要預設選中資料庫中的那個項目!
不過很不幸的,接到手的資料庫不見得是當初我們規劃的,常會接到那中資料庫表格間完全沒有設定關連的設計,導致資料庫中的內容發生「不一致」的情況。
舉個例子來說好了,假設有個「會員資料」表格中有個欄位是「會員等級」,而「會員等級」是定義在另一個表格,這兩個表格就要設定關連,但是「前人」卻沒有設定 Foreign Key,導致「某人」可能手動更新了「會員等級」資料表中的主鍵內容,造成在「會員表格」中關連不到「會員等級」的情況!
像是這樣的情況,使用 DropDownList 做 DataBinding 的時候就會發生 Exception,而且還沒辦法在 Code Behind 的地方做 try/catch 的動作!想必造成不少人困擾!!
而我們的解決方法是自己寫一個 WebControl 類別,且直接繼承 System.Web.UI.WebControls.DropDownList 類別,並覆寫(overwrite) PerformDataBinding 方法!
[code:c#]
public class DropDownList2 : DropDownList
{
protected override void PerformDataBinding(System.Collections.IEnumerable dataSource)
{
// 過濾掉 DropDownList 在 DataBinding 時可能會發生的 Exception 問題!
// 如果 Exception 發生,預設會選取第一個下拉選項!
try
{
base.PerformDataBinding(dataSource);
}
catch (ArgumentOutOfRangeException ex)
{
ArgumentOutOfRangeException o = ex;
}
}
}
[/code]
以上這段程式碼就會讓 DropDownList 在做 DataBinding 時不會發生 Exception 了,如果發生 base.PerformDataBinding() 執行失敗的時候,預設是會選中下拉選單中的「第一個選項」。
最後,要在 web.config 中註冊這個 WebControl 讓頁面可以使用,這邊就有兩種用法了:
1. 將元件註冊到 web.config 並自訂 tagPrefix
如果你是將這個 WebControl 放在 App_Code 目錄下的話,要用以下的方式宣告:
[code:html]
<configuration>
<system.web>
<pages>
<controls>
<add tagPrefix="Doggy" namespace="Doggy.UI.WebControls" assembly="App_Code, Doggy.UI.WebControls.DropDownList2"/>
</controls>
</pages>
</system.web>
</configuration>
[/code]
至於使用方法會像如下範例:
[code:html]
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>DropDownList2 測試案例</title>
</head>
<body>
<form id="form1" runat="server">
<h1>測試案例 1 : DropDownList2</h1>
<Doggy:DropDownList2 runat="server" ID="DropDownList1">
<asp:ListItem Text="List 1" Value="1"></asp:ListItem>
<asp:ListItem Text="List 2" Value="2"></asp:ListItem>
<asp:ListItem Text="List 3" Value="3"></asp:ListItem>
<asp:ListItem Text="List 4" Value="4"></asp:ListItem>
<asp:ListItem Text="List 5" Value="5"></asp:ListItem>
</Doggy:DropDownList2>
</form>
</body>
</html>
[/code]
2. 第二種比較狠一點,直接將內建的 DropDownList 都換成我們的 DropDownList2
透過 tagMapping 的方式,可以將整個網站內用到 <asp:DropDownList> 的 WebControl 都改用我們自訂的 DropDownList2 類別!
[code:html]
<configuration>
<system.web>
<pages>
<tagMapping>
<add tagType="System.Web.UI.WebControls.DropDownList"
mappedTagType="Doggy.UI.WebControls.DropDownList2" />
</tagMapping>
</pages>
</system.web>
</configuration>
[/code]
至於使用的方法,就跟用 <asp:DropDownList> 完全一模一樣啦!
[code:html]
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>DropDownList2 測試案例</title>
</head>
<body>
<form id="form1" runat="server">
<h1>測試案例 1 : DropDownList2</h1>
<asp:DropDownList runat="server" ID="DropDownList1">
<asp:ListItem Text="List 1" Value="1"></asp:ListItem>
<asp:ListItem Text="List 2" Value="2"></asp:ListItem>
<asp:ListItem Text="List 3" Value="3"></asp:ListItem>
<asp:ListItem Text="List 4" Value="4"></asp:ListItem>
<asp:ListItem Text="List 5" Value="5"></asp:ListItem>
</asp:DropDownList>
</form>
</body>
</html>
[/code]