共用方式為


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

作者 :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,並將設定為 IDUserAccounts。 在一段時間,我們將撰寫程序代碼,以使用 Membership 類別的 GetAllUsers 方法,將用戶帳戶集系結至 GridView。 如先前教學課程中所討論,GetAllUsers 方法會傳回 MembershipUserCollection 物件,這是物件的集合 MembershipUser 。 集合中的每個都包含 MembershipUserUserNameEmailIsApproved等屬性。

若要在 GridView 中顯示所需的使用者帳戶資訊,請將 GridView 的 AutoGenerateColumns 屬性設定為 False,並為 、 EmailComment 屬性新增 BoundFieldsUserName,以及 、 IsLockedOutIsOnline 屬性的 IsApprovedCheckBoxFields。 此組態可以透過控件的宣告式標記或透過 [字段] 對話框套用。 圖 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 void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    BindUserAccounts();
}

private void BindUserAccounts()
{
    UserAccounts.DataSource = Membership.GetAllUsers();
    UserAccounts.DataBind();
}

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

用戶帳戶列在 GridView 中

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

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

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

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

首先,將 Repeater 控件新增至 GridView 上方 UserAccounts 的頁面。 將 Repeater 的 ID 屬性設定為 FilteringUI。 設定 Repeater 的範本,ItemTemplate使其轉譯其 和 CommandName 屬性系結至目前陣列元素的 LinkButtonText。 如我們在將角色指派給使用者教學課程中所見,這可以使用數據系結語法來完成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 void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        BindUserAccounts();
        BindFilteringUI();
    }
}

private void BindFilteringUI()
{
    string[] filterOptions = { "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();
}

這個方法會將篩選選項指定為陣列filterOptions中的string專案。 針對陣列中的每個元素,Repeater 會轉譯 LinkButton,其和 TextCommandName 屬性會指派給陣列元素的值。

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

Repeater 清單 27 篩選 LinkButtons

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

注意

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

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

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

private string UsernameToMatch
{
 get
 {
 object o = ViewState["UsernameToMatch"];
 if (o == null)
 return string.Empty;
 else
 return (string)o;
 }
 set
 {
 ViewState["UsernameToMatch"] = value;
 }
}

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

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

private void BindUserAccounts()
{
    UserAccounts.DataSource = Membership.FindUsersByName(this.UsernameToMatch + "%");
    UserAccounts.DataBind();
}

若要只顯示使用者名稱開頭為字母 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 void FilteringUI_ItemCommand(object source, RepeaterCommandEventArgs e)
{
    if (e.CommandName == "All")
        this.UsernameToMatch = string.Empty;
    else
        this.UsernameToMatch e.CommandName;
    BindUserAccounts();
}

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

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

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

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

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

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

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

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

注意

如需有關預設和自定義分頁之間的差異,以及實作自定義分頁所涉及的挑戰,請參閱 有效率地透過大量數據分頁

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

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

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

注意

FindUsersByName 回的數據會依使用者名稱排序;無法自定義排序準則。

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

其中一個選項是建立 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 int PageIndex
{
 get
 {
 object o = ViewState["PageIndex"];
 if (o == null)
 return 0;
 else
 return (int)o;
 }
 set
 {
 ViewState["PageIndex"] = value;
 }
}

private int PageSize
{
 get
 {
 return 10;
 }
}

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

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

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

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

private void BindUserAccounts()
{
 int totalRecords;
 UserAccounts.DataSource = Membership.FindUsersByName(this.UsernameToMatch + "%",this.PageIndex, this.PageSize, out totalRecords);
 UserAccounts.DataBind();

 // Enable/disable the paging interface
 bool visitingFirstPage = (this.PageIndex == 0);
 lnkFirst.Enabled = !visitingFirstPage;
 lnkPrev.Enabled = !visitingFirstPage;

 int lastPageIndex = (totalRecords - 1) / this.PageSize;
 bool visitingLastPage = (this.PageIndex >= lastPageIndex);
 lnkNext.Enabled = !visitingLastPage;
 lnkLast.Enabled = !visitingLastPage;
}

請注意,正在分頁的記錄總數是由 方法的最後一個參數 FindUsersByName 所決定。 這是 out 參數,因此我們必須先宣告變數來保存此值 () totalRecords ,然後使用 關鍵詞作為前置 out 詞。

傳回指定的用戶帳戶頁面之後,會根據檢視第一頁或最後一頁的數據,啟用或停用四個 LinkButton。

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

protected void lnkFirst_Click(object sender, EventArgs e)
{
 this.PageIndex = 0;
 BindUserAccounts();
}

protected void lnkPrev_Click(object sender, EventArgs e)
{
 this.PageIndex -= 1;
 BindUserAccounts();
}

protected void lnkNext_Click(object sender, EventArgs e)
{
 this.PageIndex += 1;
 BindUserAccounts();
}

protected void lnkLast_Click(object sender, EventArgs e)
{
 // Determine the total number of records
 int totalRecords;
 Membership.FindUsersByName(this.UsernameToMatch + "%", this.PageIndex,this.PageSize, out totalRecords);
 // Navigate to the last page index
 this.PageIndex = (totalRecords - 1) / this.PageSize;
 BindUserAccounts();
}

圖 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 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com