在 GridView+FormView 示範資料 新增/修改/刪除(進階篇:伺服器控制項) 一文中,示範了擴展 GridView 及 FormView 控制項,讓 GridView 可以透過屬性與 FormView 做關連來處理資料的「新增/修改/刪除」的動作。因為在該案例中,只使用 FormView 的 EditTemplate 同時處理「新增」及「修改」的動作,所以還需要自行撰寫部分程式碼去判斷控制項在新增或修改的啟用狀態,例如編號欄位在新增時為啟用,修改時就不啟用。在該文最後也提及其實有辨法讓這個案例達到零程式碼的目標,那就是讓控制項 (如 TextBox) 自行判斷所在的 FormView 的 CurrentMode,自行決定本身是否要「啟用/不啟用」、「顯示/隱藏」等狀態。本文以 TextBox 為例,說明如何修改 TextBox 讓它可以達到上述的需求。
在 GridView+FormView 示範資料 新增/修改/刪除(進階篇:伺服器控制項) 一文中,示範了擴展 GridView 及 FormView 控制項,讓 GridView 可以透過屬性與 FormView 做關連來處理資料的「新增/修改/刪除」的動作。因為在該案例中,只使用 FormView 的 EditTemplate 同時處理「新增」及「修改」的動作,所以還需要自行撰寫部分程式碼去判斷控制項在新增或修改的啟用狀態,例如編號欄位在新增時為啟用,修改時就不啟用。在該文最後也提及其實有辨法讓這個案例達到零程式碼的目標,那就是讓控制項 (如 TextBox) 自行判斷所在的 FormView 的 CurrentMode,自行決定本身是否要「啟用/不啟用」、「顯示/隱藏」等狀態。本文以 TextBox 為例,說明如何修改 TextBox 讓它可以達到上述的需求。
程式碼下載:ASP.NET Server Control - Day27.rar
Northwnd 資料庫下載:NORTHWND.rar
一、TBFormViewModeState 類別
我們先定義 EControlState (控制項狀態) 列舉,描述控制項在特定模式的狀態為何。
''' <summary>
''' 控制項狀態列舉。
''' </summary>
Public Enum EControlState
''' <summary>
''' 不設定。
''' </summary>
NotSet = 0
''' <summary>
''' 啟用。
''' </summary>
Enable = 1
''' <summary>
''' 不啟用。
''' </summary>
Disable = 2
''' <summary>
''' 隱藏。
''' </summary>
Hide = 3
End Enum
再來定義 TBFormViewModeState 類別,用來設定控制項在各種 FormView 模式 (瀏覽、新增、修改) 中的控制項狀態。
''' <summary>
''' 依 FormViewMode 來設定控制項狀態。
''' </summary>
< _
Serializable(), _
TypeConverter(GetType(ExpandableObjectConverter)) _
> _
Public Class TBFormViewModeState
Private FInsertMode As EControlState = EControlState.NotSet
Private FEditMode As EControlState = EControlState.NotSet
Private FBrowseMode As EControlState = EControlState.NotSet
''' <summary>
''' 在新增模式(FormViewMode=Insert)的控制項狀態。
''' </summary>
< _
NotifyParentProperty(True), _
DefaultValue(GetType(EControlState), "NotSet") _
> _
Public Property InsertMode() As EControlState
Get
Return FInsertMode
End Get
Set(ByVal value As EControlState)
FInsertMode = value
End Set
End Property
''' <summary>
''' 在編輯模式(FormViewMode=Edit)的控制項狀態。
''' </summary>
< _
NotifyParentProperty(True), _
DefaultValue(GetType(EControlState), "NotSet") _
> _
Public Property EditMode() As EControlState
Get
Return FEditMode
End Get
Set(ByVal value As EControlState)
FEditMode = value
End Set
End Property
''' <summary>
''' 在瀏覽模式(FormViewMode=ReadOnly)的控制項狀態。
''' </summary>
< _
NotifyParentProperty(True), _
DefaultValue(GetType(EControlState), "NotSet") _
> _
Public Property BrowseMode() As EControlState
Get
Return FBrowseMode
End Get
Set(ByVal value As EControlState)
FBrowseMode = value
End Set
End Property
End Class
定義為 TBFormViewModeState 型別的屬性是屬於複雜屬性,要套用 TypeConverter(GetType(ExpandableObjectConverter)),讓該屬性可在屬性視窗 (PropertyGrid) 擴展以便設定屬性值,如下圖所示。
二、讓 TextBox 控制項可自行維護狀態
接下來擴展 TextBox 控制項,繼承 TextBox 命名為 TBTextBox。新增 FormViewModeState 屬性 (TBFormViewModeState 型別),依 FormView Mode 來設定控制項狀。並覆寫 PreRender 方法,在此方法中呼叫 DoFormViewModeStatus 私有方法,依 FormView 的模式來處理控制項狀態。
''' <summary>
''' 文字框控制項。
''' </summary>
< _
Description("文字框控制項。"), _
ToolboxData("<{0}:TBTextBox runat=server></{0}:TBTextBox>") _
> _
Public Class TBTextBox
Inherits TextBox
Private FFormViewModeState As TBFormViewModeState
''' <summary>
''' 依 FormViewMode 來設定控制項狀態。
''' </summary>
< _
Description("依 FormViewMode 來設定控制項狀態。"), _
Category(WebCommon.Category.Behavior), _
NotifyParentProperty(True), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
PersistenceMode(PersistenceMode.InnerProperty), _
DefaultValue("") _
> _
Public ReadOnly Property FormViewModeState() As TBFormViewModeState
Get
If FFormViewModeState Is Nothing Then
FFormViewModeState = New TBFormViewModeState
End If
Return FFormViewModeState
End Get
End Property
''' <summary>
''' 處理控制項狀態。
''' </summary>
''' <param name="ControlStatus">控制項狀態。</param>
Private Sub DoControlStatus(ByVal ControlStatus As EControlState)
Select Case ControlStatus
Case EControlState.Enable
Me.Enabled = True
Case EControlState.Disable
Me.Enabled = False
Case EControlState.Hide
Me.Visible = False
End Select
End Sub
''' <summary>
''' 依 FormView 的模式來處理控制項狀態。
''' </summary>
Private Sub DoFormViewModeStatus()
Dim oFormView As FormView
'若控制項置於 FormView 中,則依 FormView 的模式來處理控制項狀態
If TypeOf Me.BindingContainer Is FormView Then
oFormView = DirectCast(Me.BindingContainer, FormView)
Select Case oFormView.CurrentMode
Case FormViewMode.Insert
DoControlStatus(Me.FormViewModeState.InsertMode)
Case FormViewMode.Edit
DoControlStatus(Me.FormViewModeState.EditMode)
Case FormViewMode.ReadOnly
DoControlStatus(Me.FormViewModeState.BrowseMode)
End Select
End If
End Sub
''' <summary>
''' 覆寫。引發 PreRender 事件。
''' </summary>
Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
MyBase.OnPreRender(e)
'依 FormView 的模式來處理控制項狀態
DoFormViewModeStatus()
End Sub
End Class
三、測試程式
1. 設定控制項相關屬性
我們使用 Northwnd 資料庫的 Products資料表為例,以 GridView+FormView 示範資料「新增/修改/刪除」的操作。在頁面拖曳 SqlDataSource 控制項後,在頁面上的使用 TBGridView 來顯示瀏覽資料。TBGridView 的 FormViewID 設為關連的 TBFormVIew 控制項;另外有使用到 TBCommandField,設定 ShowHeaderNewButton=True,讓命令列具有「新增」鈕。
<bee:TBGridView ID="TBGridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="SqlDataSource1" CellPadding="4" ForeColor="#333333"
GridLines="None" AllowPaging="True" FormViewID="TBFormView1">
<RowStyle BackColor="#EFF3FB" />
<Columns>
<bee:TBCommandField ShowDeleteButton="True" ShowEditButton="True"
ShowHeaderNewButton="True" >
</bee:TBCommandField>
'省略
</Columns>
</bee:TBGridView>
接下來設定做為新增、編輯使用的 TBFormView 控制項,我們只使用 EditItemTemplate 來同時處理新增、刪除,所以 EditItemTemplate 需要同時具有「新增」、「更新」、「取消」三個按鈕。其中 ProductID 為主索引欄位,所以我們使用 TBTextBox 來繫結 ProductID 欄位,設定 FormViewModeState.InsertMode="Enable" 使控制項在新增模式時為可編輯,設定 FormViewModeState.EditMode="Disable" 使控制項在修改模式是唯讀的。
<bee:TBFormView ID="TBFormView1" runat="server" DataKeyNames="ProductID" DataSourceID="SqlDataSource1"
DefaultMode="Edit" SingleTemplate="EditItemTemplate" BackColor="White" BorderColor="#CCCCCC"
BorderStyle="None" BorderWidth="1px" CellPadding="3" GridLines="Both" Visible="False">
<FooterStyle BackColor="White" ForeColor="#000066" />
<RowStyle ForeColor="#000066" />
<EditItemTemplate>
ProductID:
<bee:TBTextBox ID="TextBox1" runat="server" Text='<%# Bind("ProductID") %>'>
<FormViewModeState EditMode="Disable" InsertMode="Enable">
</FormViewModeState>
</bee:TBTextBox>
'省略
<asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="True" CommandName="Insert"
Text="新增" />
<asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
Text="更新" />
<asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False"
CommandName="Cancel" Text="取消" />
</EditItemTemplate>
</bee:TBFormView>
2. 測試新增模式
接下來執行程式,一開始為瀏覽模式,以 TBGridView 來呈現資料。
按下 Header 的「新增」鈕,就會隱藏 TBGridView,而切換到 TBFormView 的新增模式。其中繫結 ProductID 欄位的 TBTextBox 為可編輯模式,而下方的按鈕只會顯示「新增」及「取消」鈕。
在新增模式輸入完畢後,按下「新增」鈕,資料錄就會被寫入資料庫。
3. 測試修改模式
接下來測試修改模式,按下「編輯」鈕,就會隱藏 TBGridView,而切換到 TBFormView 的修改模式。其中繫結 ProductID 欄位的 TBTextBox 為唯讀模式,而下方的按鈕只會顯示「更新」及「取消」鈕。
在修改模式輸入完畢後,按下「更新」鈕,資料錄就會被寫入資料庫。
4. 頁面程式碼
示範了上述的操作後,接下來我們回頭看一下頁面的程式碼。你沒看錯,筆者也沒貼錯,真的是一行程式碼都沒有,因為所有相關動作都由控制項處理掉了。
Partial Class Day27
Inherits System.Web.UI.Page
End Class
備註:本文同步發佈於「第一屆iT邦幫忙鐵人賽」,如果你覺得這篇文章對您有幫助,記得連上去推鑒此文增加人氣 ^^
http://ithelp.ithome.com.tw/question/10013233
http://ithelp.ithome.com.tw/question/10013239
http://ithelp.ithome.com.tw/question/10013241