建置介面從許多個使用者帳戶中選取一個 (C#)
在本教學課程中,我們將建置具有分頁、可篩選網格線的使用者介面。 特別是,我們的使用者介面將包含一系列 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.aspx
和 RecoverPassword.aspx
。
此時,這四個頁面應該有兩個內容控件,每個主版頁面的 ContentPlaceHolders 各有一個: MainContent
和 LoginContent
。
<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.config
至 Administration
資料夾,並設定其 <authorization>
元素以允許系統管理員角色中的使用者,並拒絕所有其他使用者。
<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<allow roles="Administrators" />
<deny users="*"/>
</authorization>
</system.web>
</configuration>
此時,專案的 方案總管 看起來應該類似圖 1 中顯示的螢幕快照。
圖 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
。 集合中的每個都包含 MembershipUser
、UserName
、 Email
IsApproved
等屬性。
若要在 GridView 中顯示所需的使用者帳戶資訊,請將 GridView 的 AutoGenerateColumns
屬性設定為 False,並為 、 Email
和 Comment
屬性新增 BoundFieldsUserName
,以及 、 IsLockedOut
和 IsOnline
屬性的 IsApproved
CheckBoxFields。 此組態可以透過控件的宣告式標記或透過 [字段] 對話框套用。 圖 3 顯示 [欄位] 對話框的螢幕快照,之後[自動產生字段] 複選框已取消核取,且已新增並設定 BoundFields 和 CheckBoxFields。
圖 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 會列出系統中所有使用者的使用者名稱、電子郵件位址和其他相關帳戶資訊。
圖 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,其和 Text
CommandName
屬性會指派給陣列元素的值。
圖 5 顯示 ManageUsers.aspx
透過瀏覽器檢視時的頁面。
圖 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 開頭的用戶帳戶。
圖 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。
圖 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
有了就地分頁介面和新增 的 PageIndex
和 PageSize
屬性,我們就可以更新 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) 。
圖 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