While working on a project there was a requirement for creating a Multiselect DropDownList that will have the following features:

The following snapshot gives you an idea about the same.

multiselect dropdownlist

By default ASP.NET do not have such type of control. But anyways ASP.NET has provided us with a way that you can create your own custom web user control by combining multiple other controls such as web server, html controls, etc. Well for implementing this control I’d made use of bootstrap multiselect control because looking at the requirement bootstrap multiselect fits the best.

Bootstrap multiselect control comes with a lot of configuration option through which user can customize its default behavior and look & feel. For configuring these options inside our user control we’ve made use of properties which returns or sets values stored inside the hidden fields.

Let’s get into the code now.

I’m using VS2013 for creating ASP.NET web application. I’m naming my project as DummyWebApp. Inside my solution I’m creating a new folder with the name User Control and within this folder I’m adding a new component named “Web User Control”. I’ve named my web user control as “AutoCompleteDdl”.

The following is the AutoCompleteDdl.aspx code.

  1. <%@ Control Language="C#" AutoEventWireup="true" CodeFile="AutoCompleteDdl.ascx.cs" Inherits="UserControl_AutoCompleteDdl" %>
  2. <div style="width: 380px;" id="divAutoComplete" runat="server">
  3. <asp:HiddenField ID="hdnButtonWidth" runat="server" Value="320px" />
  4. <asp:HiddenField ID="hdnNonSelectedText" runat="server" Value="--Select--" />
  5. <asp:HiddenField ID="hdnIncludeSelectAllOption" runat="server" Value="false" />
  6. <asp:HiddenField ID="hdnSelectAllText" runat="server" Value="All" />
  7. <asp:HiddenField ID="hdnEnableFiltering" runat="server" Value="False" />
  8. <asp:HiddenField ID="hdnEnableFilteringIgnoreCase" runat="server" Value="False" />
  9. <asp:HiddenField ID="hdnDisableIfEmpty" runat="server" Value="False" />
  10. <asp:HiddenField ID="hdnMaxHeight" runat="server" Value="200" />
  11. <asp:HiddenField ID="hdnFilterPlaceholder" runat="server" Value="Search for something..." />
  12. <asp:HiddenField ID="hdnAllSelectedText" runat="server" Value="No option left..." />
  13. <asp:HiddenField ID="hdnText" runat="server" />
  14. <asp:HiddenField ID="hdnValue" runat="server" />
  15. <asp:ListBox ID="ddlAutoCompleteSelect" runat="server" Style="width: 350px;"
  16. SelectionMode="Multiple">
  17. </asp:ListBox>
  18. <p>
  19. <asp:Label ID="lblSelectedItems" runat="server" Style="word-wrap: break-word; height: 120px;
  20. float: left; overflow-y: auto;"></asp:Label>
  21. </p>
  22. </div>
As you can see that I’m making use of some hidden fields for maintaining data between server and client and there is a ListBox for allowing user with multiselect option or single select option. Hidden fields will basically maintain values used for configuring our bootstrap multiselect control. I’ve provided user with properties against each hidden field with which user (who will be using the control on their page) just need to set to get the multiselect user control in action. These hidden fields are basically going to set / configure our bootstrap multiselect control.

The following is the code for AutoCompleteDdl.aspx.cs file.
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.UI;
  6. using System.Web.UI.WebControls;
  7. public partial class UserControl_AutoCompleteDdl : System.Web.UI.UserControl
  8. {
  9. #region Variable Declaration
  10. private string _text;
  11. private string _value;
  12. private List<SelectModel> _dataSource;
  13. private ListSelectionMode _selectionMode;
  14. private const string _dataTextField = "Text";
  15. private const string _dataValueField = "Value";
  16. #endregion
  17. #region Properties
  18. /// <summary>
  19. /// Set the placeholder for the DropDownlist.
  20. /// </summary>
  21. public string NonSelectedText
  22. {
  23. get { return hdnNonSelectedText.Value; }
  24. set { hdnNonSelectedText.Value = value; }
  25. }
  26. /// <summary>
  27. /// Get Or Set the value whether select all option should be there or not.
  28. /// </summary>
  29. public bool IncludeSelectAllOption
  30. {
  31. get { return Convert.ToBoolean(hdnIncludeSelectAllOption.Value); }
  32. set { hdnIncludeSelectAllOption.Value = Convert.ToString(value); }
  33. }
  34. public bool EnableFiltering
  35. {
  36. get { return Convert.ToBoolean(hdnEnableFiltering.Value); }
  37. set { hdnEnableFiltering.Value = Convert.ToString(value); }
  38. }
  39. /// <summary>
  40. /// Configure the Type of DropDownlist it is. For e.g. whether single select or multi select.
  41. /// </summary>
  42. public ListSelectionMode SelectionMode
  43. {
  44. get { return _selectionMode; }
  45. set
  46. {
  47. _selectionMode = value;
  48. if (value == ListSelectionMode.Single)
  49. {
  50. ddlAutoCompleteSelect.SelectionMode = ListSelectionMode.Single;
  51. }
  52. else
  53. {
  54. ddlAutoCompleteSelect.SelectionMode = ListSelectionMode.Multiple;
  55. }
  56. }
  57. }
  58. /// <summary>
  59. /// Set the Width of the Combo
  60. /// </summary>
  61. public string ButtonWidth
  62. {
  63. get { return hdnButtonWidth.Value; }
  64. set
  65. {
  66. hdnButtonWidth.Value = value;
  67. lblSelectedItems.Style.Add("width", hdnButtonWidth.Value);
  68. }
  69. }
  70. /// <summary>
  71. /// To set text search enabled
  72. /// </summary>
  73. public bool Enabled
  74. {
  75. get { return ddlAutoCompleteSelect.Enabled; }
  76. set { ddlAutoCompleteSelect.Enabled = value; }
  77. }
  78. /// <summary>
  79. /// To set Data Source for Control
  80. /// </summary>
  81. public List<SelectModel> DataSource
  82. {
  83. set
  84. {
  85. _dataSource = value;
  86. ddlAutoCompleteSelect.DataSource = value;
  87. ddlAutoCompleteSelect.DataBind();
  88. }
  89. }
  90. /// <summary>
  91. /// To set Text field
  92. /// </summary>
  93. public string DataTextField
  94. {
  95. get { return ddlAutoCompleteSelect.DataTextField; }
  96. set { ddlAutoCompleteSelect.DataTextField = _dataTextField; }
  97. }
  98. /// <summary>
  99. /// To set Value field
  100. /// </summary>
  101. public string DataValueField
  102. {
  103. get { return ddlAutoCompleteSelect.DataValueField; }
  104. set { ddlAutoCompleteSelect.DataValueField = _dataValueField; }
  105. }
  106. /// <summary>
  107. /// Get the value of the Selected Items from the dropdownlist.
  108. /// </summary>
  109. public string Value
  110. {
  111. get
  112. {
  113. string strValue = string.Empty;
  114. return hdnValue.Value;
  115. }
  116. }
  117. /// <summary>
  118. /// Get the text of the Selected Items from the dropdownlist.
  119. /// </summary>
  120. public string Text
  121. {
  122. get
  123. {
  124. string strText = string.Empty;
  125. return hdnText.Value;
  126. }
  127. }
  128. public bool DisableIfEmpty
  129. {
  130. get { return Convert.ToBoolean(hdnDisableIfEmpty.Value); }
  131. set { hdnDisableIfEmpty.Value = Convert.ToString(value); }
  132. }
  133. public int MaxHeight
  134. {
  135. get { return Convert.ToInt32(hdnMaxHeight.Value); }
  136. set { hdnMaxHeight.Value = Convert.ToString(value); }
  137. }
  138. public string SelectAllText
  139. {
  140. get { return hdnSelectAllText.Value; }
  141. set { hdnSelectAllText.Value = value; }
  142. }
  143. public bool EnableFilteringIgnoreCase
  144. {
  145. get { return Convert.ToBoolean(hdnEnableFilteringIgnoreCase.Value); }
  146. set { hdnEnableFilteringIgnoreCase.Value = Convert.ToString(value); }
  147. }
  148. public string FilterPlaceholder
  149. {
  150. get { return hdnFilterPlaceholder.Value; }
  151. set { hdnFilterPlaceholder.Value = value; }
  152. }
  153. #endregion
  154. protected void Page_Load(object sender, EventArgs e)
  155. {
  156. try
  157. {
  158. if (!(string.IsNullOrEmpty(hdnText.Value) && string.IsNullOrEmpty(hdnValue.Value)))
  159. {
  160. var selectedItemsText = hdnText.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
  161. var selectedItemsValue = hdnValue.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
  162. foreach (ListItem item in ddlAutoCompleteSelect.Items)
  163. {
  164. if ((selectedItemsText.Contains(item.Text) && selectedItemsValue.Contains(item.Value)))
  165. {
  166. //selecting the item at server side.
  167. item.Selected = true;
  168. }
  169. }
  170. }
  171. }
  172. catch (Exception ex)
  173. {
  174. throw ex;
  175. }
  176. }
  177. protected void Page_PreRender(object sender, System.EventArgs e)
  178. {
  179. try
  180. {
  181. //Registering the scripts file used by the user control. Alternatively you can also set these files inside your master page or the web page on which you are going to use it.
  182. ScriptManager.RegisterClientScriptInclude(this, this.GetType(), "bootStrapJs", ResolveUrl("~/Scripts/bootstrap.min.js"));
  183. ScriptManager.RegisterClientScriptInclude(this, this.GetType(), "bootStrapMultiSelectJs", ResolveUrl("~/Scripts/bootstrap-multiselect.js"));
  184. ScriptManager.RegisterClientScriptInclude(this, this.GetType(), "autoCompleteDdlJs", ResolveUrl("~/Scripts/app/AutoCompleteDdl.js"));
  185. }
  186. catch (Exception ex)
  187. {
  188. throw ex;
  189. }
  190. }
  191. }
For configuring multiselect with custom features, here is the script file for the usercontrol.

AutoCompleteDdl.js
  1. //Controls
  2. var labelId = '';
  3. var hdnTextId = '';
  4. var hdnValueId = '';
  5. var ddlCntrl = '';
  6. //Property Values Controls
  7. var hdnButtonWidth = '';
  8. var hdnNonSelectedText = '';
  9. var hdnIncludeSelectAllOption = '';
  10. var hdnSelectAllText = '';
  11. var hdnEnableFiltering = '';
  12. var hdnEnableFilteringIgnoreCase = '';
  13. var hdnDisableIfEmpty = '';
  14. var hdnMaxHeight = '';
  15. var hdnFilterPlaceholder = '';
  16. var hdnAllSelectedText = '';
  17. //Helper variables
  18. var selectedItemsText = '';
  19. var selectedItemsValue = '';
  20. //This function is used for converting C# boolean values to
  21. //Javascript boolean Values.
  22. function convertToBoolean(value) {
  23. return (value === "true");
  24. }
  25. //Writing function inside the pageLoad function is for rebinding the events after partial postback.
  26. function pageLoad() {
  27. $(document).ready(function () {
  28. //Iterating over the no of select element whose Id contains value of "ddlAutoCompleteSelect". This iteration is necessary because on a single page the user control might can be used on
  29. //single times or multiple times. For e.g. if the user contorl is placed inside a gridview row, or if the user control is used on some kind of registration forms.
  30. $("select[id*='ddlAutoCompleteSelect']").each(function () {
  31. ddlCntrl = $(this);
  32. divUCParent = $(ddlCntrl).parent();
  33. //retrieving the Id's of the controls/elements
  34. labelId = ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "lblSelectedItems");
  35. hdnTextId = ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnText");
  36. hdnValueId = ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnValue");
  37. //retrieving the values of the hidden fields/ property values
  38. hdnButtonWidth = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnButtonWidth")).val();
  39. hdnNonSelectedText = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnNonSelectedText")).val();
  40. hdnIncludeSelectAllOption = convertToBoolean($("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnIncludeSelectAllOption")).val().toString().toLowerCase());
  41. hdnSelectAllText = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnSelectAllText")).val();
  42. hdnEnableFiltering = convertToBoolean($("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnEnableFiltering")).val().toString().toLowerCase());
  43. hdnEnableFilteringIgnoreCase = convertToBoolean($("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnEnableFilteringIgnoreCase")).val().toString().toLowerCase());
  44. hdnDisableIfEmpty = convertToBoolean($("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnDisableIfEmpty")).val().toString().toLowerCase());
  45. hdnMaxHeight = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnMaxHeight")).val();
  46. hdnFilterPlaceholder = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnFilterPlaceholder")).val();
  47. hdnAllSelectedText = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnAllSelectedText")).val();
  48. selectedItemsText = $("#" + hdnTextId).val();
  49. selectedItemsValue = $("#" + hdnValueId).val();
  50. //configuring the bootstrap multiselect with the custom specification which user has set through the properties.
  51. $(this).multiselect({
  52. buttonWidth: hdnButtonWidth,
  53. includeSelectAllOption: hdnIncludeSelectAllOption,
  54. enableFiltering: hdnEnableFiltering,
  55. enableCaseInsensitiveFiltering: hdnEnableFilteringIgnoreCase,
  56. selectAllText: hdnSelectAllText,
  57. nonSelectedText: hdnNonSelectedText,
  58. disableIfEmpty: hdnDisableIfEmpty,
  59. maxHeight: hdnMaxHeight,
  60. filterPlaceholder: hdnFilterPlaceholder,
  61. allSelectedText: hdnAllSelectedText,
  62. buttonText: function (options, select) {
  63. if (options.length === 0) {
  64. return this.nonSelectedText;
  65. }
  66. else if (this.allSelectedText && options.length == $('option', $(select)).length) {
  67. if (this.selectAllNumber) {
  68. return this.allSelectedText + ' (' + options.length + ')';
  69. }
  70. else {
  71. return this.allSelectedText;
  72. }
  73. }
  74. else {
  75. var selected = '';
  76. options.each(function () {
  77. var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
  78. //forming a list.
  79. selected += "<li>" + label + "</li>";
  80. });
  81. return selected;
  82. }
  83. },
  84. onChange: function (option, checked, select) {
  85. var options = this.getSelected();
  86. // resetting the updateButtonText event values
  87. if (this.options.enableHTML) {
  88. $('.multiselect .multiselect-selected-text', this.$container).html(hdnNonSelectedText);
  89. }
  90. else {
  91. $('.multiselect .multiselect-selected-text', this.$container).text(hdnNonSelectedText);
  92. }
  93. $('.multiselect', this.$container).attr('title', hdnNonSelectedText);
  94. //setting the Label data by forming a unordered list.
  95. $("#" + labelId).html("<ul>" + this.options.buttonText(options, this.$select) + "</ul>");
  96. //resetting the variable values to ''
  97. selectedItemsText = '';
  98. selectedItemsValue = '';
  99. //iterating over the selected options and appending it to the variables
  100. $.each(options, function (index, option) {
  101. selectedItemsText += option.text + ",";
  102. selectedItemsValue += option.value + ",";
  103. });
  104. selectedItemsText = selectedItemsText.substring(0, selectedItemsText.lastIndexOf(","));
  105. selectedItemsValue = selectedItemsValue.substring(0, selectedItemsValue.lastIndexOf(","));
  106. //finally storing the value to the respective hidden fields.
  107. $("#" + hdnTextId).val(selectedItemsText);
  108. $("#" + hdnValueId).val(selectedItemsValue);
  109. }
  110. });
  111. });
  112. //incase of post back get the data from the hiddenField hdnText and hdnValues for restoring it back to the userControl selected values.
  113. if (selectedItemsText != '' && selectedItemsValue != '') {
  114. var selectedTextsArr = selectedItemsText.split(",");
  115. var selectedValuesArr = selectedItemsValue.split(",");
  116. $("#" + divUCParent.attr("id")).children(".btn-group").find("ul.multiselect-container li").each(function () {
  117. var currentLI = $(this);
  118. var anchorElement = $(this).find("a");
  119. if (anchorElement != undefined && anchorElement.length != 0) {
  120. var checkBox = $(anchorElement).children("label[class='checkbox']").children("input[type='checkbox']");
  121. var checkBoxValue = $(checkBox).val();
  122. if ($.inArray(checkBoxValue, selectedValuesArr) > -1) {
  123. $(currentLI).addClass("active");
  124. $(checkBox).trigger("change");
  125. }
  126. }
  127. });
  128. }
  129. });
  130. }
Note:

  1. Here in my user control script I’m overriding the method buttonText of bootstrap multiselect to behave in the way my user control requires i.e. form a list of selected Items and display it as an unordered list.

  2. And in the onChange event I’m resetting the default behavior of bootstrap multiselect dropdown. Bootstrap multiselect dropdown has the default behavior of setting the selected items text on the button title. In this event I’m resetting this behavior and displaying the selected items inside Label control below my user control in an unordered list.

  3. If you look at user control .aspx file, for the hidden field I’ve provided some default values. If in case the user while implementing the user control on his page doesn’t pass value for any of the property then the default value for that property from the hidden field would be used or else the new value set by the user would be used to configure the bootstrap multiselect control.

  4. Well here I just took those properties which I’m using to configure my bootstrap control. But apart from these properties there are lot of other properties which you may require to configure your application.

  5. You implementing other properties you need to do the same which we did. By creating a property in the .apsx.cs file and by adding a new hidden field in the .aspx file.

  6. Writing code in your user control script file for reading the value of that hidden field.

Now our user control is ready and we need to take it on our page to make it working. For this I’ve added a new webpage in my application and I’ve registered the user control on my page. The following is my .aspx code for the web page.

Default.aspx

  1. <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
  2. <%@ Register Src="UserControl/AutoCompleteDdl.ascx" TagName="AutoCompleteDdl" TagPrefix="uc1" %>
  3. <!DOCTYPE html>
  4. <html xmlns="http://www.w3.org/1999/xhtml">
  5. <head runat="server">
  6. <title>Bootstrap Multiselect</title>
  7. <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" />
  8. <link rel="stylesheet" type="text/css" href="Style/bootstrap-multiselect.css" />
  9. <script src="Scripts/jquery-1.9.1.min.js"></script>
  10. </head>
  11. <body>
  12. <form id="form1" runat="server">
  13. <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
  14. <div class="container">
  15. <div class="row">
  16. <div class="col-md-12">
  17. <h3>Bootstrap MultiSelect Dropdownlist</h3>
  18. <asp:UpdatePanel ID="udpMain" runat="server">
  19. <ContentTemplate>
  20. <uc1:AutoCompleteDdl ID="ddlAutoComplete" runat="server" IncludeSelectAllOption="false"
  21. ButtonWidth="320px" SelectAllText="All" NonSelectedText="--Select Option--" MaxHeight="400"
  22. EnableFiltering="true" FilterPlaceholder="Search For Something..." SelectForm="Multiple"
  23. PlaceHolder="Select a Value" />
  24. <p>
  25. <asp:Button ID="btnGet" runat="server" Text="Get Data" OnClick="btnGet_Click" />
  26. </p>
  27. <p>
  28. <asp:Label ID="lblData" runat="server" />
  29. </p>
  30. </ContentTemplate>
  31. </asp:UpdatePanel>
  32. </div>
  33. </div>
  34. </div>
  35. </form>
  36. </body>
  37. </html>
Note:

  1. Here I’ve added the user control on my page.

  2. I’m setting the required ButtonWidth, whether the dropdownlist should enable filtration or not and other such bootstrap properties with the help of properties defined inside the user control.

Default.aspx.cs

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.UI;
  6. using System.Web.UI.WebControls;
  7. public partial class _Default : System.Web.UI.Page
  8. {
  9. List<SelectModel> lstData = new List<SelectModel>();
  10. protected void Page_Load(object sender, EventArgs e)
  11. {
  12. if (!IsPostBack)
  13. {
  14. for (int i = 0; i < 100; i++)
  15. {
  16. lstData.Add(new SelectModel() { Value = "Item " + i, Text = "Item " + i });
  17. }
  18. ddlAutoComplete.DataValueField = "Value";
  19. ddlAutoComplete.DataTextField = "Text";
  20. //Setting the data source for the dropdownlist
  21. ddlAutoComplete.DataSource = lstData;
  22. }
  23. }
  24. protected void btnGet_Click(object sender, EventArgs e)
  25. {
  26. string value = ddlAutoComplete.Value;
  27. string text = ddlAutoComplete.Text;
  28. lblData.Text = "<b>Value: </b>" + value + "<br/><b>Text: </b>" + text;
  29. }
  30. }
Now just run the application and you’ll see the following output.

output

Select some items from the dropdownlist and you’ll find those selected items below our dropdownlist in an unordered list.

dropdownlist

You may also try filtering the data by typing something in the “Search For Something” textbox.

Search For Something

While entering the value in the filter textbox make sure you do it in proper case since we’ve set the “EnableFilteringIgnoreCase” property value to its default value by not setting it inside the default.aspx page.

EnableFilteringIgnoreCase

Now the point is of maintaining the data between postback. For testing this we’ve added a button control “Get Data” on the page and a label control which will display the selected items text and value. Just click on the Get Data button and after postback here is the output.

Get Data button