Preferred Language:

Listing 10.17 - MultiSelectList.cs

Illustrates how to create a MultiSelectList custom control.

Listing 10.17 - MultiSelectList.cs (C#)
Copy

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("--&gt;");
            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("&lt;--");
            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.

Listing 10.18 - MultiSelectList.js
Copy

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;
};

The following page demonstrates the MultiSelectList control.

Listing 10.19 - ShowMultiSelectList.aspx (C#)
Copy

<%@ 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>