Illustrates how to create a MultiSelectList custom control.
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace MyControls
{
/// <summary>
/// Enables you to select mulitple list items
/// from two list boxes
/// </summary>
[ValidationProperty("SelectedItem")]
public class MultiSelectList : ListControl, IPostBackDataHandler
{
private int _rows = 5;
private Unit _UnSelectedWidth = Unit.Parse("300px");
private Unit _SelectedWidth = Unit.Parse("300px");
/// <summary>
/// This control is contained in a div
/// tag
/// </summary>
protected override HtmlTextWriterTag TagKey
{
get { return HtmlTextWriterTag.Div; }
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
writer.AddStyleAttribute("position", "relative");
base.AddAttributesToRender(writer);
}
/// <summary>
/// The number of rows of list items to display
/// </summary>
public int Rows
{
get { return _rows; }
set { _rows = value; }
}
/// <summary>
/// Name passed to client-side script
/// </summary>
private string BaseName
{
get { return ClientID + ClientIDSeparator; }
}
/// <summary>
/// Name of unselected items list box
/// </summary>
private string UnselectedListName
{
get { return BaseName + "unselected"; }
}
/// <summary>
/// Name of selected items list box
/// </summary>
private string SelectedListName
{
get { return BaseName + "selected"; }
}
/// <summary>
/// Name of hidden input field
/// </summary>
private string HiddenName
{
get { return BaseName + "hidden"; }
}
/// <summary>
/// Register client scripts
/// </summary>
protected override void OnPreRender(EventArgs e)
{
Page.RegisterRequiresPostBack(this);
// Register hidden field
Page.ClientScript.RegisterHiddenField(HiddenName, String.Empty);
// Register Include File
if (!Page.ClientScript.IsClientScriptIncludeRegistered("MultiSelectList"))
Page.ClientScript.RegisterClientScriptInclude("MultiSelectList", Page.ResolveUrl("~/ClientScripts/MultiSelectList.js"));
// Register submit script
string submitScript = String.Format("multiSelectList_submit('{0}')", BaseName);
Page.ClientScript.RegisterOnSubmitStatement(this.GetType(), this.ClientID, submitScript);
base.OnPreRender(e);
}
/// <summary>
/// Render list boxes and buttons
/// </summary>
protected override void RenderContents(HtmlTextWriter writer)
{
// Render Unselected
RenderUnselected(writer);
// Render Buttons
RenderButtons(writer);
// Render Selected
RenderSelected(writer);
// Render clear break
writer.AddStyleAttribute("clear", "both");
writer.RenderBeginTag(HtmlTextWriterTag.Br);
writer.RenderEndTag();
}
/// <summary>
/// Render the buttons
/// </summary>
private void RenderButtons(HtmlTextWriter writer)
{
writer.AddStyleAttribute("float", "left");
writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, "10px");
writer.AddStyleAttribute(HtmlTextWriterStyle.TextAlign, "center");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
string addScript = String.Format("return multiSelectList_add('{0}');", BaseName);
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, addScript);
writer.AddAttribute(HtmlTextWriterAttribute.Title, "Add Item");
writer.RenderBeginTag(HtmlTextWriterTag.Button);
writer.Write("-->");
writer.RenderEndTag();
writer.WriteBreak();
string removeScript = String.Format("return multiSelectList_remove('{0}');", BaseName);
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, removeScript);
writer.AddAttribute(HtmlTextWriterAttribute.Title, "Remove Item");
writer.RenderBeginTag(HtmlTextWriterTag.Button);
writer.Write("<--");
writer.RenderEndTag();
writer.RenderEndTag();
}
/// <summary>
/// Render unselected list box
/// </summary>
private void RenderUnselected(HtmlTextWriter writer)
{
writer.AddStyleAttribute("float", "left");
writer.AddAttribute(HtmlTextWriterAttribute.Size, _rows.ToString());
writer.AddStyleAttribute(HtmlTextWriterStyle.Width, _UnSelectedWidth.ToString());
writer.AddAttribute(HtmlTextWriterAttribute.Id, UnselectedListName);
writer.AddAttribute(HtmlTextWriterAttribute.Name, UnselectedListName);
writer.AddAttribute(HtmlTextWriterAttribute.Multiple, "true");
writer.RenderBeginTag(HtmlTextWriterTag.Select);
foreach (ListItem item in Items)
if (!item.Selected)
RenderListItem(writer, item);
writer.RenderEndTag();
//writer.RenderEndTag();
}
/// <summary>
/// Render selected list items
/// </summary>
private void RenderSelected(HtmlTextWriter writer)
{
writer.AddStyleAttribute("float", "left");
writer.AddAttribute(HtmlTextWriterAttribute.Size, _rows.ToString());
writer.AddStyleAttribute(HtmlTextWriterStyle.Width, _SelectedWidth.ToString());
writer.AddAttribute(HtmlTextWriterAttribute.Id, SelectedListName);
writer.AddAttribute(HtmlTextWriterAttribute.Name, SelectedListName);
writer.AddAttribute(HtmlTextWriterAttribute.Multiple, "true");
writer.RenderBeginTag(HtmlTextWriterTag.Select);
foreach (ListItem item in Items)
if (item.Selected)
RenderListItem(writer, item);
writer.RenderEndTag();
//writer.RenderEndTag();
}
/// <summary>
/// Render a list item
/// </summary>
private void RenderListItem(HtmlTextWriter writer, ListItem item)
{
writer.AddAttribute(HtmlTextWriterAttribute.Value, item.Value);
writer.RenderBeginTag(HtmlTextWriterTag.Option);
writer.Write(item.Text);
writer.RenderEndTag();
}
/// <summary>
/// Process postback data
/// </summary>
public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
EnsureDataBound();
ClearSelection();
string values = postCollection[HiddenName];
if (values != String.Empty)
{
string[] splitValues = values.Split(',');
foreach (string value in splitValues)
{
Items.FindByValue(value).Selected = true;
}
}
return false;
}
/// <summary>
/// Required by the IPostBackDataHandler interface
/// </summary>
public void RaisePostDataChangedEvent()
{
}
}
}
The MultiSelectList control uses the following client-side JavaScript file.
function multiSelectList_add(baseName)
{
var unselectedList = document.getElementById(baseName + 'unselected');
var selectedList = document.getElementById(baseName + 'selected');
// Copy selected items
var selectedItems = Array.clone(unselectedList.options);
for (var i=0;i < selectedItems.length;i++)
{
if (selectedItems[i].selected)
{
var item = unselectedList.removeChild(selectedItems[i]);
selectedList.appendChild(item);
}
}
// Prevent post
return false;
}
function multiSelectList_remove(baseName)
{
var unselectedList = document.getElementById(baseName + 'unselected');
var selectedList = document.getElementById(baseName + 'selected');
// Copy unselected items
var selectedItems = Array.clone(selectedList.options);
for (var i=0;i < selectedItems.length;i++)
{
if (selectedItems[i].selected)
{
var item = selectedList.removeChild(selectedItems[i]);
unselectedList.appendChild(item);
}
}
// Prevent post
return false;
}
// This function executes when the page
// is submitted. It stuffs all of the
// selected items into a hidden field
function multiSelectList_submit(baseName)
{
var hidden = document.getElementById(baseName + 'hidden');
var selectedList = document.getElementById(baseName + 'selected');
var values = new Array();
for (var i=0;i<selectedList.options.length;i++)
values.push(selectedList.options[i].value);
hidden.value = values.join(',');
}
Array.clone = function(arrItems)
{
var results = [];
for (var i=0;i < arrItems.length; i++)
results.push(arrItems[i]);
return results;
};
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="MyControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
protected void btnSubmit_Click(object sender, EventArgs e)
{
foreach (ListItem item in MultiSelectList1.Items)
if (item.Selected)
lblSelected.Text += String.Format("<li>{0} ({1})",item.Text,item.Value);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Show MultiSelectList</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<b>Movies:</b>
<asp:RequiredFieldValidator
id="val"
ControlToValidate="MultiSelectList1"
Text="Required"
Runat="server" />
<custom:MultiSelectList
id="MultiSelectList1"
DataSourceID="srcMovies"
DataTextField="Title"
DataValueField="Id"
Runat="server" />
<asp:SqlDataSource
id="srcMovies"
SelectCommand="SELECT Id, Title FROM Movies"
ConnectionString="<%$ ConnectionStrings:Movies %>"
Runat="server" />
<p>
<asp:Button
id="btnSubmit"
Text="Submit"
Runat="server" OnClick="btnSubmit_Click" />
</p>
<hr />
<asp:Label
id="lblSelected"
EnableViewState="false"
Runat="server" />
</div>
</form>
</body>
</html>