在 ListBoxes 用户控件之间移动、排序、搜索和过滤项






4.44/5 (6投票s)
如何使用 ASP.NET (C#) 在 ListBoxes 之间移动、排序、过滤和搜索项目,并将其制作成可重用的用户控件
引言
在本示例中,我将解释如何使用 ASP.NET (C#) 中的 `Generic Collection IList` 实现搜索、过滤、排序和移动两个 `ListBox` 之间的项目,并将其制作成可重用的用户控件。
使用 `Generic collection` 可以将 `ListBox` 绑定到任何泛型类型 `IList`,并且还将解释如何绑定两个 `ListBox`,以及在目标 `Listbox` 中已存在的情况下,删除源 `Listbox` 中所有已存在的记录,以便在需要更新数据库中已保存的记录时使用。
背景
几乎所有 Web 应用程序都有安全模块,用于向用户授予权限和特权。在这种场景下,开发人员需要两个 `Listbox` 来分别显示可用权限和已授予权限。他们需要在应用程序中花费大量精力来开发此功能。
源代码
第一部分将解释如何使用两个 `ListBox` 开发用户控件,并添加这两个 `ListBox` 的功能。之后,我们将用户控件添加到页面中并调用它。
用户控件代码
- 在 .NET 2008 中创建一个新的网站,并通过 "添加新项" 从解决方案中添加用户控件。将其命名为 `ucListBox`。
ASCX 代码
<%@ Control Language="C#" AutoEventWireup="false"
CodeBehind="ucListBox.ascx.cs" Inherits="ListBox_Demo.ucListBox" %>
<script type="text/javascript" language="javascript">
var ddlText, ddlValue, ddl, lblMesg;
function CacheItems() {
ddlText = new Array();
ddlValue = new Array();
ddl = document.getElementById("<%=lstAvailable.ClientID %>");
for (var i = 0; i < ddl.options.length; i++) {
ddlText[ddlText.length] = ddl.options[i].text;
ddlValue[ddlValue.length] = ddl.options[i].value;
}
}
window.onload = CacheItems;
function FilterItems(value) {
ddl.options.length = 0;
for (var i = 0; i < ddlText.length; i++) {
if (ddlText[i].toLowerCase().indexOf(value) != -1) {
AddItem(ddlText[i], ddlValue[i]);
}
}
if (ddl.options.length == 0) {
AddItem("", "");
}
}
function AddItem(text, value) {
var opt = document.createElement("option");
opt.text = text;
opt.value = value;
ddl = document.getElementById("<%=lstAvailable.ClientID %>");
ddl.options.add(opt);
}
</script>
<table width="100%" border="0" id="tblSearch" runat="server" visible="true">
<tr>
<td style="width: 19%; height: 24px;" align="left" runat="server" id="tdd">
<span style="font-size: 8pt"><strong>
<asp:Label runat="server" Text="Search" ID="lblSearch"></asp:Label>
</strong></span>
</td>
<td>
<asp:TextBox ID="txtSearch" runat="server"
onkeyup="FilterItems(this.value)"></asp:TextBox><br />
</td>
</tr>
</table>
<table width="80%" border="0">
<tr align="left">
<td align="left">
<!-- Start list box-->
<table width="100%">
<tr>
<td valign="top">
<table border="0" width="100%">
<tr>
<td>
<span style="font-size: 8pt"><strong>
<asp:Label runat="server"
ID="lblAvailable" Text="Available"></asp:Label>
</strong></span>
</td>
</tr>
<tr>
<td style="height: 200px">
<asp:ListBox ID="lstAvailable"
runat="server" Height="100%" SelectionMode="Multiple"
Width="300px" Font-Size="10pt"></asp:ListBox>
</td>
</tr>
</table>
</td>
<td align="center" valign="top">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
</td>
</tr>
<tr>
<td>
<br />
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td>
<asp:ImageButton ID="btnAddAll"
ImageUrl="~/Images/GrantAll.png"
runat="server" CausesValidation="False" />
</td>
</tr>
<tr>
<td>
<asp:ImageButton ID="btnAdd"
ImageUrl="~/Images/Grant.png"
runat="server" CausesValidation="False" />
</td>
</tr>
<tr>
<td>
<asp:ImageButton ID="btnRemove"
ImageUrl="~/Images/Revoke.png"
runat="server" CausesValidation="False" />
</td>
</tr>
<tr>
<td>
<asp:ImageButton ID="btnRemoveAll"
ImageUrl="~/Images/RevokeAll.png" runat="server"
CausesValidation="False" />
</td>
</tr>
</table>
</td>
<td valign="top">
<table width="100%">
<tr>
<td>
<span style="font-size: 8pt"><strong>
<asp:Label runat="server"
ID="lblAdded" Text="Added"></asp:Label>
</strong></span>
</td>
</tr>
<tr>
<td style="height: 200px">
<asp:ListBox ID="lstAdded"
runat="server" Font-Size="10pt"
Height="100%" SelectionMode="Multiple"
Width="300px"></asp:ListBox>
</td>
</tr>
<tr>
<td>
</td>
</tr>
</table>
</td>
<td>
<table width="100%">
<tr>
<td>
<asp:ImageButton ID="btnMoveUp"
runat="server" ImageUrl="~/Images/MoveUp.png"
CausesValidation="False" />
</td>
</tr>
<tr>
<td>
<asp:ImageButton ID="btnMoveDown"
runat="server" CausesValidation="False"
ImageUrl="~/Images/MoveDown.png" />
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- end list box-->
</td>
</tr>
</table>
在上面的代码中,我添加了一个标签和一个文本框,用于在名为 `lstAvailable` 的可用 `ListBox` 中搜索和过滤记录。
我使用了两个 `listbox` - `lstAvailable` 和 `lstAdded`,以及 Move, Next, Pervious, First, Up 和 Down 按钮,用于在 `ListBox` 之间移动和排序项目。
上述三个 JavaScript 方法负责过滤和搜索过程。这些方法的详细信息如下所示:
CacheItems
此方法在窗口 `onload` 事件上调用。此方法的工作是填充文本和值数组,用于缓存可用列表 (`Available List`) 的 `ListBox` 项目。
FilterItems
当搜索文本框 (`Search TextBox`) 中触发 `keyup` 事件时,将调用此方法。此方法搜索字符串片段,并过滤可用列表 (`Available List`) 的 `ListBox` 项目。
AddItem
此方法用于向 `ListBox` 添加新项目。
C# 代码
在代码隐藏中添加 `System.Collections`,并添加以下代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
namespace ListBox_Demo
{
public partial class ucListBox : System.Web.UI.UserControl
{
#region Property
private IList _DataSourceAvailable = null;
private IList _DataSourceAdded = null;
private string _dataTextFieldAvailable = string.Empty;
private string _dataValueFieldAvailable = string.Empty;
private string _dataTextFieldAdded = string.Empty;
private string _dataValueFieldAdded = string.Empty;
private string _availableItemText = "Available Roles"; //Resources.Common.AvailableItemText;
private string _addedItemText = "Assgin Roles";// Resources.Common.AddedItemText;
protected ArrayList arlList = new ArrayList();
/// <summary>
/// Gets or sets the available item text.
/// </summary>
/// <value>The available item text.</value>
public string AvailableItemHeaderText
{
get { return _availableItemText; }
set { _availableItemText = value; }
}
/// <summary>
/// Gets or sets the added items text.
/// </summary>
/// <value>The added items text.</value>
public string AddedItemsHeaderText
{
get { return _addedItemText; }
set { _addedItemText = value; }
}
/// <summary>
/// Gets the available items.
/// </summary>
/// <value>The available items.</value>
public ListItemCollection AvailableItems
{
get { return lstAvailable.Items; }
}
/// <summary>
/// Gets the added items.
/// </summary>
/// <value>The added items.</value>
public ListItemCollection AddedItems
{
get { return lstAdded.Items; }
}
/// <summary>
/// Gets or sets the data source for the available items listbox.
/// </summary>
/// <value>The data source for available items.</value>
public IList DataSourceAvailable
{
get { return _DataSourceAvailable; }
set { _DataSourceAvailable = value; }
}
/// <summary>
/// Gets or sets the data source for the added items listbox.
/// </summary>
/// <value>The data source for added items.</value>
public IList DataSourceAdded
{
get { return _DataSourceAdded; }
set { _DataSourceAdded = value; }
}
/// <summary>
/// Gets or sets the data text field available.
/// </summary>
/// <value>The data text field available.</value>
public string DataTextFieldAvailable
{
get { return _dataTextFieldAvailable; }
set { _dataTextFieldAvailable = value; }
}
/// <summary>
/// Gets or sets the data value field available.
/// </summary>
/// <value>The data value field available.</value>
public string DataValueFieldAvailable
{
get { return _dataValueFieldAvailable; }
set { _dataValueFieldAvailable = value; }
}
/// <summary>
/// Gets or sets the data text field added.
/// </summary>
/// <value>The data text field added.</value>
public string DataTextFieldAdded
{
get { return _dataTextFieldAdded; }
set { _dataTextFieldAdded = value; }
}
/// <summary>
/// Gets or sets the data value field added.
/// </summary>
/// <value>The data value field added.</value>
public string DataValueFieldAdded
{
get { return _dataValueFieldAdded; }
set { _dataValueFieldAdded = value; }
}
#endregion
#region Method
protected void Page_Load(object sender, EventArgs e)
{
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Initializer();
}
private void Initializer()
{
btnAdd.Click += new ImageClickEventHandler(btnAdd_Click);
btnAddAll.Click += new ImageClickEventHandler(btnAddAll_Click);
btnRemove.Click += new ImageClickEventHandler(btnRemove_Click);
btnRemoveAll.Click += new ImageClickEventHandler(btnRemoveAll_Click);
btnMoveUp.Click += new ImageClickEventHandler(btnMoveUp_Click);
btnMoveDown.Click += new ImageClickEventHandler(btnMoveDown_Click);
//lblAdded.Text = this.AddedItemsHeaderText;
//lblAvailable.Text = this.AvailableItemHeaderText;
}
public void BindAvailableList()
{
//Set the Header Text of the Available and Added Items
lblAdded.Text = this.AddedItemsHeaderText;
lblAvailable.Text = this.AvailableItemHeaderText;
//Bind the Added List Control
lstAvailable.DataSource = this.DataSourceAvailable;
lstAvailable.DataTextField = this.DataTextFieldAvailable;
lstAvailable.DataValueField = this.DataValueFieldAvailable;
lstAvailable.DataBind();
}
public void BindAddedList()
{
//Set the Header Text of the Available and Added Items
lblAdded.Text = this.AddedItemsHeaderText;
lblAvailable.Text = this.AvailableItemHeaderText;
//Bind the Available List Control
lstAdded.DataSource = this.DataSourceAdded;
lstAdded.DataTextField = this.DataTextFieldAdded;
lstAdded.DataValueField = this.DataValueFieldAdded;
lstAdded.DataBind();
}
public void BindList()
{
//Set the Header Text of the Available and Added Items
lblAdded.Text = this.AddedItemsHeaderText;
lblAvailable.Text = this.AvailableItemHeaderText;
//Bind the Available and Added List Controls
lstAdded.DataSource = this.DataSourceAdded;
lstAdded.DataTextField = this.DataTextFieldAdded;
lstAdded.DataValueField = this.DataValueFieldAdded;
lstAdded.DataBind();
lstAvailable.DataSource = this.DataSourceAvailable;
lstAvailable.DataTextField = this.DataTextFieldAvailable;
lstAvailable.DataValueField = this.DataValueFieldAvailable;
lstAvailable.DataBind();
#region Remove intersection Record
ArrayList ary = new ArrayList();
for (int i = 0; i < lstAvailable.Items.Count; i++)
{
for (int j = 0; j < lstAdded.Items.Count; j++)
{
if (lstAvailable.Items[i].Value == lstAdded.Items[j].Value)
{
// lstAvailable.RemoveAt(i);
if (!ary.Contains(lstAvailable.Items[i]))
{
ary.Add(lstAvailable.Items[i]);
j = -1;
}
break;
}
}
}
for (int i = 0; i < ary.Count; i++)
{
lstAvailable.Items.Remove(((ListItem)ary[i]));
}
#endregion
ScriptManager.RegisterStartupScript(this.Page, typeof(Page), "myscript", "CacheItems();", true);
//ScriptManager.RegisterStartupScript(Page, typeof(Page), "myscript", "UploadFileToParent();", true);
}
#endregion
#region Navigation
/// <summary>
/// Add all the selected items from the Available Items to the Added Items
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/>
/// instance containing the event data.</param>
protected void btnAdd_Click(object sender, EventArgs e)
{
if (lstAvailable.SelectedIndex >= 0)
{
for (int i = 0; i < lstAvailable.Items.Count; i++)
{
if (lstAvailable.Items[i].Selected)
{
if (!arlList.Contains(lstAvailable.Items[i]))
arlList.Add(lstAvailable.Items[i]);
}
}
for (int i = 0; i < arlList.Count; i++)
{
if (!lstAdded.Items.Contains((ListItem)arlList[i]))
lstAdded.Items.Add((ListItem)arlList[i]);
lstAvailable.Items.Remove((ListItem)arlList[i]);
}
}
}
/// <summary>
/// Add all the items from the Available items to the Added Items
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="
/// System.EventArgs"/> instance containing the event data.</param>
protected void btnAddAll_Click(object sender, EventArgs e)
{
foreach (ListItem list in lstAvailable.Items)
{
lstAdded.Items.Add(list);
}
lstAvailable.Items.Clear();
}
/// <summary>
/// Moves the Selected items from the Added items to the Available items
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="
/// System.EventArgs"/> instance containing the event data.</param>
protected void btnRemove_Click(object sender, EventArgs e)
{
if (lstAdded.SelectedIndex >= 0)
{
for (int i = 0; i < lstAdded.Items.Count; i++)
{
if (lstAdded.Items[i].Selected)
{
if (!arlList.Contains(lstAdded.Items[i]))
arlList.Add(lstAdded.Items[i]);
}
}
for (int i = 0; i < arlList.Count; i++)
{
if (!lstAvailable.Items.Contains((ListItem)arlList[i]))
lstAvailable.Items.Add((ListItem)arlList[i]);
lstAdded.Items.Remove((ListItem)arlList[i]);
}
}
}
/// <summary>
/// Moves all the items from the Added items to the Available items
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void btnRemoveAll_Click(object sender, EventArgs e)
{
foreach (ListItem list in lstAdded.Items)
{
lstAvailable.Items.Add(list);
}
lstAdded.Items.Clear();
}
/// <summary>
/// Move item to upwards
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void btnMoveDown_Click(object sender, ImageClickEventArgs e)
{
try
{
int startindex = lstAdded.Items.Count - 1;
for (int i = startindex; i > -1; i--)
{
if (lstAdded.Items[i].Selected)//identify the selected item
{
//swap with the lower item(move down)
if (i < startindex && !lstAdded.Items[i + 1].Selected)
{
ListItem bottom = lstAdded.Items[i];
lstAdded.Items.Remove(bottom);
lstAdded.Items.Insert(i + 1, bottom);
lstAdded.Items[i + 1].Selected = true;
}
}
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// Move Item To down Words
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void btnMoveUp_Click(object sender, ImageClickEventArgs e)
{
try
{
for (int i = 0; i < lstAdded.Items.Count; i++)
{
if (lstAdded.Items[i].Selected)//identify the selected item
{
//swap with the top item(move up)
if (i > 0 && !lstAdded.Items[i - 1].Selected)
{
ListItem bottom = lstAdded.Items[i];
lstAdded.Items.Remove(bottom);
lstAdded.Items.Insert(i - 1, bottom);
lstAdded.Items[i - 1].Selected = true;
}
}
}
}
catch (Exception ex)
{
}
}
#endregion
}
}
上述三个 **binds** 函数用于绑定 `ListBox`,每个函数都有不同的功能,其描述如下:
BindAvailableList()
如果您想绑定 `Available ListBox`,则从 aspx 页面调用此方法,并且需要从 aspx 页面分配以下属性:
- `DataSourceAvailable`: 传递 `IList` Collection。
- `DataTextFieldAvailable`: `ListBox` 中显示的必需属性名称。
- `DataValueFieldAvailable`: 应该是 `ListBox` 中唯一的必需属性 ID。
BindAddedList()
如果您想绑定 `Added ListBox`,则从 aspx 页面调用此方法,并且需要从 aspx 页面分配以下属性:
- `DataSourceAdded`: 传递 `IList` Collection。
- `DataTextFieldAdded`: `ListBox` 中显示的必需属性名称。
- `DataValueFieldAdded`: 应该是 `ListBox` 中唯一的必需属性 ID。
BindList()
如果您想绑定 `Available` 和 `Added` 两个 `ListBox`,并且需要删除 `Added ListBox` 中已存在的所有项目,则从 aspx 页面调用此函数,并且需要从 aspx 页面分配以下属性:
- `DataSourceAvailable`: 传递 `IList` Collection。
- `DataTextFieldAvailable`: `ListBox` 中显示的必需属性名称。
- `DataValueFieldAvailable`: 应该是 `ListBox` 中唯一的必需属性 ID。
- `DataSourceAdded`: 传递 `IList` Collection。
- `DataTextFieldAdded`: `ListBox` 中显示的必需属性名称。
- `DataValueFieldAdded`: 应该是 `ListBox` 中唯一的必需属性 ID。
注意
如果希望从 aspx 页面更改 `ListBox` 的标题,则需要 `AvailableItemHeaderText` 和 `AddedItemsHeaderText`,它们是可选的。
GUI 页面代码
Aspx 代码
在 `default.aspx` 页面中添加 `ucListBox` 用户控件,当您在 .NET 2008 中创建网站时,该页面会自动添加。
<%@ Register src="ucListBox.ascx" tagname="ucListBox" tagprefix="uc1" %>
为了展示用户控件的完整工作流程,我在页面中创建了三个按钮,并调用用户控件的所有三个绑定方法。
<%@ Page Language="C#" AutoEventWireup="false" CodeBehind="Default.aspx.cs" Inherits="ListBox_Demo._Default" %>
<%@ Register src="ucListBox.ascx" tagname="ucListBox" tagprefix="uc1" %>
<!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></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnAvailable" runat="server" Text="Bind Available List"
onclick="btnAvailable_Click" />
<asp:Button ID="btnAdded" runat="server" Text="Bind Added List"
onclick="btnAdded_Click" />
<asp:Button ID="btnBoth" runat="server" Text="Bind Both"
onclick="btnBoth_Click" />
<uc1:ucListBox ID="ucListBox1" runat="server" />
</div>
</form>
</body>
</html>
C# 代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
namespace ListBox_Demo
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
void AvailableItems()
{
List<Roles> lstRole = new List<Roles>();
Roles objRoles = new Roles();
objRoles.ID = 1;
objRoles.Name = "Admin";
lstRole.Add(objRoles);
objRoles = new Roles();
objRoles.ID = 2;
objRoles.Name = "Manager";
lstRole.Add(objRoles);
objRoles = new Roles();
objRoles.ID = 3;
objRoles.Name = "Supervisor";
lstRole.Add(objRoles);
objRoles = new Roles();
objRoles.ID = 4;
objRoles.Name = "Employee";
lstRole.Add(objRoles);
objRoles = new Roles();
objRoles.ID = 5;
objRoles.Name = "User";
lstRole.Add(objRoles);
objRoles = new Roles();
objRoles.ID = 6;
objRoles.Name = "Client";
lstRole.Add(objRoles);
ucListBox1.DataTextFieldAvailable = "Name";
ucListBox1.DataValueFieldAvailable = "ID";
ucListBox1.DataSourceAvailable = lstRole;
ucListBox1.AvailableItemHeaderText = "Available Permissions";
ucListBox1.AddedItemsHeaderText = "Added Permissions";
}
void SelectedItems()
{
List<Roles> lstRole = new List<Roles>();
Roles objRoles = new Roles();
objRoles.ID = 1;
objRoles.Name = "Admin";
lstRole.Add(objRoles);
objRoles = new Roles();
objRoles.ID = 2;
objRoles.Name = "Manager";
lstRole.Add(objRoles);
objRoles = new Roles();
objRoles.ID = 4;
objRoles.Name = "Employee";
lstRole.Add(objRoles);
objRoles = new Roles();
objRoles.ID = 5;
objRoles.Name = "User";
lstRole.Add(objRoles);
ucListBox1.DataTextFieldAdded = "Name";
ucListBox1.DataValueFieldAdded = "ID";
ucListBox1.DataSourceAdded = lstRole;
ucListBox1.AvailableItemHeaderText = "Available Permissions";
ucListBox1.AddedItemsHeaderText = "Added Permissions";
}
protected void btnAvailable_Click(object sender, EventArgs e)
{
AvailableItems();
ucListBox1.BindAvailableList();
}
protected void btnAdded_Click(object sender, EventArgs e)
{
SelectedItems();
ucListBox1.BindAddedList();
}
protected void btnBoth_Click(object sender, EventArgs e)
{
AvailableItems();
SelectedItems();
ucListBox1.BindList();
}
}
public class Roles
{
public int ID { get; set; }
public string Name { get; set; }
}
}
我创建了两个函数 `SelectedItems()` 和 `AvailableItems()` 来填充硬编码的列表,并在三个不同的按钮点击事件中调用它们。
关注点
编写这些示例很烦人,因为它们太大了,占用了我大量的时间。