共用方式為


建置介面從許多個使用者帳戶中選取一個 (VB)

作者 :Scott Mitchell

在本教學課程中,我們將建置具有分頁、可篩選格線的使用者介面。 特別是,我們的使用者介面將包含一系列 LinkButtons,可根據使用者名稱的起始字母和 GridView 控制項來篩選結果,以顯示相符的使用者。 首先,我們會列出 GridView 中的所有使用者帳戶。 然後,在步驟 3 中,我們將新增篩選 LinkButtons。 步驟 4 會查看分頁篩選的結果。 後續教學課程會使用步驟 2 到 4 中建構的介面,以針對特定使用者帳戶執行系統管理工作。

簡介

在 [ 將角色指派給使用者] 教學課程中,我們已為系統管理員建立一個基本的介面,以選取使用者並管理她的角色。 具體而言,介面會向系統管理員呈現所有使用者的下拉式清單。 當有數十個以上的使用者帳戶,但對於具有數百或數千個帳戶的網站而言,這類介面很適合。 可篩選的分頁格線更適合具有大型使用者基底的網站使用者介面。

在本教學課程中,我們將建置這類使用者介面。 特別是,我們的使用者介面將包含一系列 LinkButtons,可根據使用者名稱的起始字母和 GridView 控制項來篩選結果,以顯示相符的使用者。 首先,我們會列出 GridView 中的所有使用者帳戶。 然後,在步驟 3 中,我們將新增篩選 LinkButtons。 步驟 4 會查看分頁篩選的結果。 後續教學課程會使用步驟 2 到 4 中建構的介面,以針對特定使用者帳戶執行系統管理工作。

現在就開始吧!

步驟 1:新增 ASP.NET 網頁

在本教學課程和下兩個教學課程中,我們將檢查各種與系統管理相關的功能與功能。 我們需要一系列 ASP.NET 網頁,以實作這些教學課程中檢查的主題。 讓我們建立這些頁面並更新網站地圖。

從在名為 Administration 的專案中建立新資料夾開始。 接下來,將兩個新的 ASP.NET 網頁新增至 資料夾,並將每個頁面與 Site.master 主版頁面連結。 為頁面命名:

  • ManageUsers.aspx
  • UserInformation.aspx

此外,將兩個頁面新增至網站的根目錄: ChangePassword.aspxRecoverPassword.aspx

此時,這四個頁面應該有兩個內容控制項,每個主版頁面的 ContentPlaceHolders 各有一個: MainContentLoginContent

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" Runat="Server"> 
</asp:Content> 
<asp:Content ID="Content2" ContentPlaceHolderID="LoginContent" Runat="Server"> 
</asp:Content>

我們想要針對這些頁面顯示 ContentPlaceHolder 的主版頁面預設標記 LoginContent 。 因此,移除 Content 控制項的 Content2 宣告式標記。 這麼做之後,頁面的標記應該只包含一個 Content 控制項。

資料夾中的 ASP.NET 網頁 Administration 僅供系統管理使用者使用。 我們已在建立和管理角色教學課程中 將系統管理員角色新增至系統;請限制存取此角色的這兩個頁面。 若要達成此目的,請將檔案新增 Web.configAdministration 資料夾,並設定其 <authorization> 元素以允許系統管理員角色中的使用者,並拒絕所有其他使用者。

<?xml version="1.0"?> 
<configuration> 
 <system.web> 
 <authorization> 
 <allow roles="Administrators" /> 
 <deny users="*"/> 
 </authorization> 
 </system.web> 
</configuration>

此時,您的專案方案總管看起來應該類似圖 1 中顯示的螢幕擷取畫面。

已將四個新頁面和Web.config檔案新增至網站

圖 1:已將四個新頁面和檔案 Web.config 新增至網站 (按一下即可檢視完整大小的影像)

最後,更新網站地圖 (Web.sitemap) 以包含頁面的專案 ManageUsers.aspx 。 在新增角色教學課程之後 <siteMapNode> ,新增下列 XML。

<siteMapNode title="User Administration" url="~/Administration/ManageUsers.aspx"/>

網站地圖更新後,請透過瀏覽器流覽網站。 如圖 2 所示,左側導覽現在包含系統管理教學課程的專案。

網站地圖包含標題為使用者管理的節點

圖 2:網站地圖包含標題為 [使用者管理] 的節點, (按一下即可檢視完整大小的影像)

步驟 2:列出 GridView 中的所有使用者帳戶

本教學課程的最終目標是建立可篩選的分頁方格,讓系統管理員可以選取要管理的使用者帳戶。 讓我們 從列出 GridView 中的所有使用者開始。 完成後,我們將新增篩選和分頁介面和功能。

ManageUsers.aspx開啟資料夾中的頁面 Administration 並新增 GridView,並將其 ID 設定為 UserAccounts [一段時間],我們會撰寫程式碼,以使用 Membership 類別的 GetAllUsers 方法將使用者帳戶集系結至 GridView。 如先前教學課程中所述,方法會 GetAllUsers 傳回 MembershipUserCollection 物件,這是 物件的集合 MembershipUser 。 集合中的每個都包含 MembershipUserUserNameEmailIsApproved 等屬性。

若要在 GridView 中顯示所需的使用者帳戶資訊,請將 GridView 的 AutoGenerateColumns 屬性設定為 False,並為 、 EmailComment 屬性新增 BoundFields UserName ,以及 、 IsLockedOutIsOnline 屬性的 IsApproved CheckBoxFields。 此組態可以透過控制項的宣告式標記或透過 [欄位] 對話方塊套用。 圖 3 顯示 [欄位] 對話方塊的螢幕擷取畫面,之後[自動產生欄位] 核取方塊已取消核取,且已新增並設定 BoundFields 和 CheckBoxFields。

將 Three BoundFields 和 Three CheckBoxFields 新增至 GridView

圖 3:將三個 BoundFields 和三個 CheckBoxField 新增至 GridView (按一下即可檢視完整大小的影像)

設定 GridView 之後,請確定其宣告式標記類似下列內容:

<asp:GridView ID="UserAccounts" runat="server" AutoGenerateColumns="False">
 <Columns>
 <asp:BoundField DataField="UserName" HeaderText="UserName" />
 <asp:BoundField DataField="Email" HeaderText="Email" />
 <asp:CheckBoxField DataField="IsApproved" HeaderText="Approved?" />
 <asp:CheckBoxField DataField="IsLockedOut" HeaderText="Locked Out?" />
 <asp:CheckBoxField DataField="IsOnline" HeaderText="Online?" />
 <asp:BoundField DataField="Comment" HeaderText="Comment" />
 </Columns>
</asp:GridView>

接下來,我們需要撰寫將使用者帳戶系結至 GridView 的程式碼。 建立名為 BindUserAccounts 的方法,以執行這項工作,然後從 Page_Load 第一頁流覽的事件處理常式呼叫它。

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
 If Not Page.IsPostBack Then
 BindUserAccounts()
 End If
End Sub

Private Sub BindUserAccounts()
 UserAccounts.DataSource = Membership.GetAllUsers()
 UserAccounts.DataBind()
End Sub

請花點時間透過瀏覽器測試頁面。 如圖 4 所示, UserAccounts GridView 會列出系統中所有使用者的使用者名稱、電子郵件地址和其他相關帳戶資訊。

使用者帳戶列在 GridView 中

圖 4:使用者帳戶列在 GridView (按一下以檢視完整大小的影像)

步驟 3:依使用者名稱的第一個字母篩選結果

UserAccountsGridView 目前會顯示所有使用者帳戶。 對於具有數百或數千個使用者帳戶的網站,使用者必須能夠快速剖析顯示的帳戶。 這可以藉由將篩選 LinkButtons 新增至頁面來完成。 讓我們將 27 個 LinkButtons 新增至頁面:一個標題為 All,以及每個字母字母的一個 LinkButton。 如果訪客按一下 [所有 LinkButton],GridView 將會顯示所有使用者。 如果他們按一下特定字母,則只會顯示使用者名稱開頭為所選字母的使用者。

我們的第一項工作是新增 27 個 LinkButton 控制項。 其中一個選項是以宣告方式建立 27 個 LinkButtons,一次一個。 更有彈性的方法是使用 Repeater 控制項搭配 ItemTemplate 轉譯 LinkButton 的 ,然後將篩選選項系結至 Repeater 做為 String 陣列。

首先,將 Repeater 控制項新增至 GridView 上方 UserAccounts 的頁面。 將 Repeater 的 ID 屬性設定為 FilteringUI 設定 Repeater 的範本, ItemTemplate 使其轉譯 LinkButton,其 TextCommandName 屬性會系結至目前的陣列元素。 如我們在將角色指派給使用者教學課程中所 見,這可以使用資料系結語法來完成 Container.DataItem 。 使用 Repeater 來 SeparatorTemplate 顯示每個連結之間的垂直線。

<asp:Repeater ID="FilteringUI" runat="server">
 <ItemTemplate>
 <asp:LinkButton runat="server" ID="lnkFilter" 
 Text='<%# Container.DataItem %>'
 CommandName='<%# Container.DataItem %>'></asp:LinkButton>
 </ItemTemplate>
 <SeparatorTemplate>|</SeparatorTemplate>
</asp:Repeater>

若要使用所需的篩選選項填入此重複項,請建立名為 BindFilteringUI 的方法。 請務必從 Page_Load 第一頁載入的事件處理常式呼叫這個方法。

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
 If Not Page.IsPostBack Then
 BindUserAccounts()
 BindFilteringUI()
 End If
End Sub

Private Sub BindFilteringUI()
 Dim filterOptions() As String = {"All", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
 FilteringUI.DataSource = filterOptions
 FilteringUI.DataBind()
End Sub

這個方法會將篩選選項指定為數組中 String 每個元素 的元素:針對陣列 filterOptions 中的每個元素,Repeater 會轉譯 LinkButton,並將其 TextCommandName 屬性指派給陣列元素的值。

圖 5 顯示 ManageUsers.aspx 透過瀏覽器檢視時的頁面。

重複程式清單 27 篩選 LinkButtons

圖 5:重複程式清單 27 篩選 LinkButtons (按一下即可檢視完整大小的影像)

注意

使用者名稱可能以任何字元開頭,包括數位和標點符號。 若要檢視這些帳戶,系統管理員必須使用 [所有 LinkButton] 選項。 或者,您可以新增 LinkButton 以傳回以數位開頭的所有使用者帳戶。 我將此專案保留為讀者的練習。

按一下任何篩選 LinkButtons 會導致回傳並引發 Repeater ItemCommand 的事件,但方格中沒有任何變更,因為我們尚未撰寫任何程式碼來篩選結果。 類別 Membership 包含FindUsersByName 方法,這個方法會傳回其使用者名稱符合指定搜尋模式的使用者帳戶。 我們可以使用這個方法來只擷取使用者名稱開頭為已篩選之 LinkButton 所指定 CommandName 字母的使用者帳戶。

從更新 ManageUser.aspx 頁面的程式碼後置類別開始,讓它包含名為 UsernameToMatch 此屬性的屬性,會在回傳之間保存使用者名稱篩選字串:

Private Property UsernameToMatch() As String
 Get
 Dim o As Object = ViewState("UsernameToMatch")
 If o Is Nothing Then
 Return String.Empty
 Else
 Return o.ToString()
 End If
 End Get
 Set(ByVal Value As String)
 ViewState("UsernameToMatch") = Value
 End Set
End Property

屬性 UsernameToMatch 會使用索引鍵 'UsernameToMatch' 將其值儲存到 ViewState 集合中。 讀取這個屬性的值時,它會檢查集合中 ViewState 是否有值存在;如果沒有,則會傳回預設值空字串。 屬性 UsernameToMatch 會呈現常見的模式,也就是保存值以檢視狀態,以便在回傳之間保存屬性的任何變更。 如需此模式的詳細資訊,請參閱 瞭解 ASP.NET 檢視狀態

接下來,更新 BindUserAccounts 方法,而不是呼叫 Membership.GetAllUsers ,它會呼叫 Membership.FindUsersByName ,並傳入附加 SQL 萬用字元 %的 UsernameToMatch 屬性值。

Private Sub BindUserAccounts()
 UserAccounts.DataSource = Membership.FindUsersByName(Me.UsernameToMatch &"%")
 UserAccounts.DataBind()
End Sub

若要只顯示使用者名稱開頭為字母 A 的使用者,請將 屬性設定 UsernameToMatch 為 A,然後呼叫 BindUserAccounts 這會導致呼叫 Membership.FindUsersByName("A%") ,這會傳回使用者名稱開頭為 A 的所有使用者。同樣地,若要傳回 所有使用者 ,請將空字串指派給 UsernameToMatch 屬性, BindUserAccounts 讓 方法叫 Membership.FindUsersByName("%") 用 ,進而傳回所有使用者帳戶。

建立 Repeater ItemCommand 事件的事件處理常式。 每當按一下其中一個篩選 LinkButtons 時,就會引發此事件;它會透過 RepeaterCommandEventArgs 物件傳遞按下的 LinkButton CommandName 值。 我們需要將適當的值指派給 UsernameToMatch 屬性,然後呼叫 BindUserAccounts 方法。 如果 為 CommandName All,請將空字串指派給 UsernameToMatch ,以便顯示所有使用者帳戶。 否則,請將 CommandName 值指派給 UsernameToMatch

Protected Sub FilteringUI_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles FilteringUI.ItemCommand
 If e.CommandName = "All" Then
 Me.UsernameToMatch = String.Empty
 Else
 Me.UsernameToMatch = e.CommandName
 End If

 BindUserAccounts()
End Sub

在此程式碼就緒後,請測試篩選功能。 第一次流覽頁面時,會顯示所有使用者帳戶, (請參閱圖 5) 。 按一下 [連結][按鈕] 會導致回傳並篩選結果,只顯示以 A 開頭的使用者帳戶。

使用篩選 LinkButtons 來顯示使用者名稱開頭為特定字母的使用者

圖 6:使用篩選 LinkButtons 顯示使用者名稱開頭為特定字母的使用者, (按一下即可檢視完整大小的影像)

步驟 4:更新 GridView 以使用分頁

圖 5 和 6 所示的 GridView 會列出從 FindUsersByName 方法傳回的所有記錄。 如果有數百個或數千個使用者帳戶,這可能會導致在檢視所有帳戶時 (多載資訊,就如同按一下 [所有 LinkButton] 或一開始流覽頁面時) 的情況。 為了協助以更容易管理的區塊呈現使用者帳戶,讓我們設定 GridView 一次顯示 10 個使用者帳戶。

GridView 控制項提供兩種類型的分頁:

  • 預設分頁 - 容易實作,但效率不佳。 簡單地說,使用預設分頁 GridView 會預期其資料來源 中的所有 記錄。 然後,它只會顯示適當的記錄頁面。
  • 自訂分頁 - 需要更多工作才能實作,但比預設分頁更有效率,因為使用自訂分頁資料來源只會傳回要顯示的精確記錄集。

在分頁到數千筆記錄時,預設和自訂分頁之間的效能差異可能相當重要。 因為我們正在建置此介面,假設可能有數百個或數千個使用者帳戶,讓我們使用自訂分頁。

注意

如需有關預設和自訂分頁之間的差異,以及實作自訂分頁所涉及的挑戰,請參閱 有效率地透過大量資料分頁。 如需預設和自訂分頁之間效能差異的一些分析,請參閱2005 SQL Server ASP.NET 中的自訂分頁

若要實作自訂分頁,我們必須先有一些機制,以擷取 GridView 所顯示的精確記錄子集。 好消息是 Membership 類別的 FindUsersByName 方法具有多載,可讓我們指定頁面索引和頁面大小,並只傳回落在該記錄範圍內的使用者帳戶。

特別是,此多載具有下列簽章: FindUsersByName(usernameToMatch, pageIndex, pageSize, totalRecords)

pageIndex參數會指定要傳回的使用者帳戶頁面;pageSize會指出每頁顯示多少筆記錄。 totalRecords參數是傳 ByRef 回使用者存放區中使用者帳戶總數的參數。

注意

FindUsersByName 回的資料會依使用者名稱排序;無法自訂排序準則。

GridView 可以設定為利用自訂分頁,但只有在系結至 ObjectDataSource 控制項時。 若要讓 ObjectDataSource 控制項實作自訂分頁,它需要兩種方法:一個方法會傳遞起始資料列索引,以及要顯示的記錄數目上限,並傳回落在該範圍內之記錄的精確子集;和 方法,傳回正在分頁的記錄總數。 多 FindUsersByName 載會接受頁面索引和頁面大小,並透過 ByRef 參數傳回記錄總數。 因此,此處的介面不符。

其中一個選項是建立 Proxy 類別,以公開 ObjectDataSource 預期的介面,然後在內部呼叫 FindUsersByName 方法。 另一個選項 - 以及我們將用於本文的選項 - 是建立自己的分頁介面,並使用該介面,而不是 GridView 的內建分頁介面。

建立第一個、上一個、下一個、最後一個分頁介面

讓我們使用 First、Previous、Next 和 Last LinkButtons 來建置分頁介面。 按一下第一個 LinkButton 時,會將使用者帶往資料的第一頁,而 Previous 則會將他傳回上一頁。 同樣地,Next 和 Last 會分別將使用者移至下一頁和最後一頁。 在 GridView 下方 UserAccounts 新增四個 LinkButton 控制項。

<p>
 <asp:LinkButton ID="lnkFirst" runat="server">  First</asp:LinkButton> |
 <asp:LinkButton ID="lnkPrev" runat="server">  Prev</asp:LinkButton> |
 <asp:LinkButton ID="lnkNext" runat="server">Next  </asp:LinkButton> |
 <asp:LinkButton ID="lnkLast" runat="server">Last  </asp:LinkButton>
</p>

接下來,為每個 LinkButton Click 的事件建立事件處理常式。

圖 7 顯示透過 Visual Web 開發人員設計檢視檢視時的四個 LinkButton。

在 GridView 下方新增 First、Previous、Next 和 Last LinkButtons

圖 7:在 GridView 下方新增 First、Previous、Next 和 Last LinkButtons (按一下即可檢視大小完整的影像)

追蹤目前的頁面索引

當使用者第一次流覽 ManageUsers.aspx 頁面或按一下其中一個篩選按鈕時,我們想要在 GridView 中顯示第一頁的資料。 不過,當使用者按一下其中一個導覽 LinkButtons 時,我們需要更新頁面索引。 若要維護頁面索引和每頁顯示的記錄數目,請將下列兩個屬性新增至頁面的程式碼後置類別:

Private Property PageIndex() As Integer
 Get
 Dim o As Object = ViewState("PageIndex")
 If o Is Nothing Then
 Return 0
 Else
 Return Convert.ToInt32(o)
 End If
 End Get
 Set(ByVal Value As Integer)
 ViewState("PageIndex") = Value
 End Set
End Property

Private ReadOnly Property PageSize() As Integer
 Get
 Return 10
 End Get
End Property

UsernameToMatch如同 屬性, PageIndex 屬性會保存其值以檢視狀態。 唯讀 PageSize 屬性會傳回硬式編碼值 10。 我邀請感興趣的讀者更新此屬性,以使用 與 相同的模式 PageIndex ,然後增強 ManageUsers.aspx 頁面,讓流覽頁面的人員可以指定每個頁面要顯示的使用者帳戶數目。

只擷取目前頁面的記錄、更新頁面索引,以及啟用和停用分頁介面 LinkButtons

有了就地分頁介面和新增 的 PageIndexPageSize 屬性,我們就可以更新 BindUserAccounts 方法,讓它使用適當的 FindUsersByName 多載。 此外,我們需要啟用或停用這個方法,視顯示的頁面而定。 檢視資料的第一頁時,應該停用 First 和 Previous 連結;檢視最後一頁時,應該停用 Next 和 Last。

以下列程式碼更新 BindUserAccounts 方法:

Private Sub BindUserAccounts()
 Dim totalRecords As Integer
 UserAccounts.DataSource = Membership.FindUsersByName(Me.UsernameToMatch + "%", Me.PageIndex, Me.PageSize, totalRecords)
 UserAccounts.DataBind()

 ' Enable/disable the paging interface
 Dim visitingFirstPage As Boolean = (Me.PageIndex = 0)
 lnkFirst.Enabled = Not visitingFirstPage
 lnkPrev.Enabled = Not visitingFirstPage

 Dim lastPageIndex As Integer = (totalRecords - 1) / Me.PageSize
 Dim visitingLastPage As Boolean = (Me.PageIndex >= lastPageIndex)
 lnkNext.Enabled = Not visitingLastPage
 lnkLast.Enabled = Not visitingLastPage
End Sub

請注意,正在分頁的記錄總數是由 方法的最後一個參數 FindUsersByName 所決定。 傳回指定的使用者帳戶頁面之後,會根據檢視第一頁或最後一頁的資料,啟用或停用四個 LinkButton。

最後一個步驟是撰寫四個 Click LinkButtons 事件處理常式的程式碼。 這些事件處理常式需要更新 PageIndex 屬性,然後透過呼叫 BindUserAccounts The First、Previous 和 Next 事件處理常式將資料重新系結至 GridView 十分簡單。 Click不過,Last LinkButton 的事件處理常式比較複雜,因為我們必須判斷要顯示多少筆記錄,才能判斷最後一頁索引。

Protected Sub lnkFirst_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkFirst.Click
 Me.PageIndex = 0
 BindUserAccounts()
End Sub

Protected Sub lnkPrev_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkPrev.Click
 Me.PageIndex -= 1
 BindUserAccounts()
End Sub

Protected Sub lnkNext_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkNext.Click
 Me.PageIndex += 1
 BindUserAccounts()
End Sub

Protected Sub lnkLast_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkLast.Click
 ' Determine the total number of records
 Dim totalRecords As Integer
 Membership.FindUsersByName(Me.UsernameToMatch + "%", Me.PageIndex, Me.PageSize, totalRecords)
 ' Navigate to the last page index
 Me.PageIndex = (totalRecords - 1) / Me.PageSize
 BindUserAccounts()
End Sub

圖 8 和 9 顯示自訂分頁介面的運作情形。 圖 8 顯示 ManageUsers.aspx 檢視所有使用者帳戶第一頁數據時的頁面。 請注意,只會顯示 13 個帳戶中的 10 個。 按一下 [下一步] 或 [最後一個] 連結會導致回傳、將 更新 PageIndex 為 1,並將使用者帳戶的第二頁系結至方格 (請參閱圖 9) 。

顯示前 10 個使用者帳戶

圖 8:前 10 個使用者帳戶會顯示 (按一下即可檢視完整大小的影像)

按一下 [下一步連結] 會顯示使用者帳戶的第二頁

圖 9:按一下 [下一個連結] 會顯示使用者帳戶的第二頁, (按一下即可檢視全大小的影像)

總結

系統管理員通常需要從帳戶清單中選取使用者。 在先前的教學課程中,我們已探討如何使用填入使用者中的下拉式清單,但此方法無法妥善調整。 在本教學課程中,我們探索了較佳的替代方法:可篩選的介面,其結果會顯示在分頁 GridView 中。 透過此使用者介面,系統管理員可以快速且有效率地找出並選取數千個使用者帳戶。

快樂的程式設計!

深入閱讀

如需本教學課程中所討論之主題的詳細資訊,請參閱下列資源:

關於作者

Scott Mitchell 是多個 ASP/ASP.NET 書籍的作者,以及 4GuysFromRolla.com 的建立者,自 1998 年起就與 Microsoft Web 技術合作。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 Scott 可以透過 mitchell@4guysfromrolla.com 在 上的部落格或透過 http://ScottOnWriting.NET 其部落格來連線。

特別感謝

本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Alicja Maziarz。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在