While working on a project there was a requirement for creating a Multiselect DropDownList that will have the following features:
- Auto complete filter.
- Control may be single select or Multiselect based on user demands.
- Select All option should be there in case of Multiselect DropDownList.
- Selected options list should be displayed below the DropDownList in list mode.
The following snapshot gives you an idea about the same.
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.
- <%@ Control Language="C#" AutoEventWireup="true" CodeFile="AutoCompleteDdl.ascx.cs" Inherits="UserControl_AutoCompleteDdl" %>
- <div style="width: 380px;" id="divAutoComplete" runat="server">
- <asp:HiddenField ID="hdnButtonWidth" runat="server" Value="320px" />
- <asp:HiddenField ID="hdnNonSelectedText" runat="server" Value="--Select--" />
- <asp:HiddenField ID="hdnIncludeSelectAllOption" runat="server" Value="false" />
- <asp:HiddenField ID="hdnSelectAllText" runat="server" Value="All" />
- <asp:HiddenField ID="hdnEnableFiltering" runat="server" Value="False" />
- <asp:HiddenField ID="hdnEnableFilteringIgnoreCase" runat="server" Value="False" />
- <asp:HiddenField ID="hdnDisableIfEmpty" runat="server" Value="False" />
- <asp:HiddenField ID="hdnMaxHeight" runat="server" Value="200" />
- <asp:HiddenField ID="hdnFilterPlaceholder" runat="server" Value="Search for something..." />
- <asp:HiddenField ID="hdnAllSelectedText" runat="server" Value="No option left..." />
- <asp:HiddenField ID="hdnText" runat="server" />
- <asp:HiddenField ID="hdnValue" runat="server" />
- <asp:ListBox ID="ddlAutoCompleteSelect" runat="server" Style="width: 350px;"
- SelectionMode="Multiple">
- </asp:ListBox>
- <p>
- <asp:Label ID="lblSelectedItems" runat="server" Style="word-wrap: break-word; height: 120px;
- float: left; overflow-y: auto;"></asp:Label>
- </p>
- </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.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
-
- public partial class UserControl_AutoCompleteDdl : System.Web.UI.UserControl
- {
- #region Variable Declaration
-
- private string _text;
- private string _value;
- private List<SelectModel> _dataSource;
- private ListSelectionMode _selectionMode;
- private const string _dataTextField = "Text";
- private const string _dataValueField = "Value";
-
- #endregion
-
- #region Properties
-
-
-
-
- public string NonSelectedText
- {
- get { return hdnNonSelectedText.Value; }
- set { hdnNonSelectedText.Value = value; }
- }
-
-
-
-
- public bool IncludeSelectAllOption
- {
- get { return Convert.ToBoolean(hdnIncludeSelectAllOption.Value); }
- set { hdnIncludeSelectAllOption.Value = Convert.ToString(value); }
- }
-
- public bool EnableFiltering
- {
- get { return Convert.ToBoolean(hdnEnableFiltering.Value); }
- set { hdnEnableFiltering.Value = Convert.ToString(value); }
- }
-
-
-
-
- public ListSelectionMode SelectionMode
- {
- get { return _selectionMode; }
- set
- {
- _selectionMode = value;
- if (value == ListSelectionMode.Single)
- {
- ddlAutoCompleteSelect.SelectionMode = ListSelectionMode.Single;
- }
- else
- {
- ddlAutoCompleteSelect.SelectionMode = ListSelectionMode.Multiple;
- }
- }
- }
-
-
-
-
- public string ButtonWidth
- {
- get { return hdnButtonWidth.Value; }
- set
- {
- hdnButtonWidth.Value = value;
- lblSelectedItems.Style.Add("width", hdnButtonWidth.Value);
- }
- }
-
-
-
-
- public bool Enabled
- {
- get { return ddlAutoCompleteSelect.Enabled; }
- set { ddlAutoCompleteSelect.Enabled = value; }
- }
-
-
-
-
- public List<SelectModel> DataSource
- {
- set
- {
- _dataSource = value;
- ddlAutoCompleteSelect.DataSource = value;
- ddlAutoCompleteSelect.DataBind();
- }
- }
-
-
-
-
- public string DataTextField
- {
- get { return ddlAutoCompleteSelect.DataTextField; }
- set { ddlAutoCompleteSelect.DataTextField = _dataTextField; }
- }
-
-
-
-
- public string DataValueField
- {
- get { return ddlAutoCompleteSelect.DataValueField; }
- set { ddlAutoCompleteSelect.DataValueField = _dataValueField; }
- }
-
-
-
-
- public string Value
- {
- get
- {
- string strValue = string.Empty;
- return hdnValue.Value;
- }
- }
-
-
-
-
- public string Text
- {
- get
- {
- string strText = string.Empty;
- return hdnText.Value;
- }
- }
-
- public bool DisableIfEmpty
- {
- get { return Convert.ToBoolean(hdnDisableIfEmpty.Value); }
- set { hdnDisableIfEmpty.Value = Convert.ToString(value); }
- }
-
- public int MaxHeight
- {
- get { return Convert.ToInt32(hdnMaxHeight.Value); }
- set { hdnMaxHeight.Value = Convert.ToString(value); }
- }
-
- public string SelectAllText
- {
- get { return hdnSelectAllText.Value; }
- set { hdnSelectAllText.Value = value; }
- }
-
- public bool EnableFilteringIgnoreCase
- {
- get { return Convert.ToBoolean(hdnEnableFilteringIgnoreCase.Value); }
- set { hdnEnableFilteringIgnoreCase.Value = Convert.ToString(value); }
- }
-
- public string FilterPlaceholder
- {
- get { return hdnFilterPlaceholder.Value; }
- set { hdnFilterPlaceholder.Value = value; }
- }
-
-
- #endregion
-
- protected void Page_Load(object sender, EventArgs e)
- {
-
- try
- {
- if (!(string.IsNullOrEmpty(hdnText.Value) && string.IsNullOrEmpty(hdnValue.Value)))
- {
- var selectedItemsText = hdnText.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- var selectedItemsValue = hdnValue.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
-
- foreach (ListItem item in ddlAutoCompleteSelect.Items)
- {
- if ((selectedItemsText.Contains(item.Text) && selectedItemsValue.Contains(item.Value)))
- {
-
- item.Selected = true;
- }
- }
- }
- }
- catch (Exception ex)
- {
- throw ex;
- }
-
- }
-
-
- protected void Page_PreRender(object sender, System.EventArgs e)
- {
- try
- {
-
- ScriptManager.RegisterClientScriptInclude(this, this.GetType(), "bootStrapJs", ResolveUrl("~/Scripts/bootstrap.min.js"));
- ScriptManager.RegisterClientScriptInclude(this, this.GetType(), "bootStrapMultiSelectJs", ResolveUrl("~/Scripts/bootstrap-multiselect.js"));
- ScriptManager.RegisterClientScriptInclude(this, this.GetType(), "autoCompleteDdlJs", ResolveUrl("~/Scripts/app/AutoCompleteDdl.js"));
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
- }
For configuring multiselect with custom features, here is the script file for the usercontrol.
AutoCompleteDdl.js
-
- var labelId = '';
- var hdnTextId = '';
- var hdnValueId = '';
-
- var ddlCntrl = '';
-
-
- var hdnButtonWidth = '';
- var hdnNonSelectedText = '';
- var hdnIncludeSelectAllOption = '';
- var hdnSelectAllText = '';
- var hdnEnableFiltering = '';
- var hdnEnableFilteringIgnoreCase = '';
- var hdnDisableIfEmpty = '';
- var hdnMaxHeight = '';
- var hdnFilterPlaceholder = '';
- var hdnAllSelectedText = '';
-
-
- var selectedItemsText = '';
- var selectedItemsValue = '';
-
-
-
- function convertToBoolean(value) {
- return (value === "true");
- }
-
-
- function pageLoad() {
- $(document).ready(function () {
-
-
-
- $("select[id*='ddlAutoCompleteSelect']").each(function () {
- ddlCntrl = $(this);
- divUCParent = $(ddlCntrl).parent();
-
-
- labelId = ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "lblSelectedItems");
- hdnTextId = ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnText");
- hdnValueId = ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnValue");
-
-
- hdnButtonWidth = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnButtonWidth")).val();
- hdnNonSelectedText = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnNonSelectedText")).val();
- hdnIncludeSelectAllOption = convertToBoolean($("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnIncludeSelectAllOption")).val().toString().toLowerCase());
- hdnSelectAllText = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnSelectAllText")).val();
- hdnEnableFiltering = convertToBoolean($("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnEnableFiltering")).val().toString().toLowerCase());
- hdnEnableFilteringIgnoreCase = convertToBoolean($("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnEnableFilteringIgnoreCase")).val().toString().toLowerCase());
- hdnDisableIfEmpty = convertToBoolean($("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnDisableIfEmpty")).val().toString().toLowerCase());
- hdnMaxHeight = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnMaxHeight")).val();
- hdnFilterPlaceholder = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnFilterPlaceholder")).val();
- hdnAllSelectedText = $("#" + ddlCntrl.attr("id").replace("ddlAutoCompleteSelect", "hdnAllSelectedText")).val();
-
-
- selectedItemsText = $("#" + hdnTextId).val();
- selectedItemsValue = $("#" + hdnValueId).val();
-
-
- $(this).multiselect({
- buttonWidth: hdnButtonWidth,
- includeSelectAllOption: hdnIncludeSelectAllOption,
- enableFiltering: hdnEnableFiltering,
- enableCaseInsensitiveFiltering: hdnEnableFilteringIgnoreCase,
- selectAllText: hdnSelectAllText,
- nonSelectedText: hdnNonSelectedText,
- disableIfEmpty: hdnDisableIfEmpty,
- maxHeight: hdnMaxHeight,
- filterPlaceholder: hdnFilterPlaceholder,
- allSelectedText: hdnAllSelectedText,
- buttonText: function (options, select) {
- if (options.length === 0) {
- return this.nonSelectedText;
- }
- else if (this.allSelectedText && options.length == $('option', $(select)).length) {
- if (this.selectAllNumber) {
- return this.allSelectedText + ' (' + options.length + ')';
- }
- else {
- return this.allSelectedText;
- }
- }
- else {
- var selected = '';
- options.each(function () {
- var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
-
- selected += "<li>" + label + "</li>";
- });
- return selected;
- }
- },
- onChange: function (option, checked, select) {
-
- var options = this.getSelected();
-
-
- if (this.options.enableHTML) {
- $('.multiselect .multiselect-selected-text', this.$container).html(hdnNonSelectedText);
- }
- else {
- $('.multiselect .multiselect-selected-text', this.$container).text(hdnNonSelectedText);
- }
- $('.multiselect', this.$container).attr('title', hdnNonSelectedText);
-
-
- $("#" + labelId).html("<ul>" + this.options.buttonText(options, this.$select) + "</ul>");
-
-
- selectedItemsText = '';
- selectedItemsValue = '';
-
-
- $.each(options, function (index, option) {
- selectedItemsText += option.text + ",";
- selectedItemsValue += option.value + ",";
- });
-
- selectedItemsText = selectedItemsText.substring(0, selectedItemsText.lastIndexOf(","));
- selectedItemsValue = selectedItemsValue.substring(0, selectedItemsValue.lastIndexOf(","));
-
-
- $("#" + hdnTextId).val(selectedItemsText);
- $("#" + hdnValueId).val(selectedItemsValue);
- }
- });
- });
-
-
- if (selectedItemsText != '' && selectedItemsValue != '') {
-
- var selectedTextsArr = selectedItemsText.split(",");
- var selectedValuesArr = selectedItemsValue.split(",");
-
- $("#" + divUCParent.attr("id")).children(".btn-group").find("ul.multiselect-container li").each(function () {
- var currentLI = $(this);
- var anchorElement = $(this).find("a");
- if (anchorElement != undefined && anchorElement.length != 0) {
- var checkBox = $(anchorElement).children("label[class='checkbox']").children("input[type='checkbox']");
- var checkBoxValue = $(checkBox).val();
-
- if ($.inArray(checkBoxValue, selectedValuesArr) > -1) {
- $(currentLI).addClass("active");
- $(checkBox).trigger("change");
- }
- }
- });
- }
-
- });
- }
Note:
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
-
- <%@ Register Src="UserControl/AutoCompleteDdl.ascx" TagName="AutoCompleteDdl" TagPrefix="uc1" %>
-
- <!DOCTYPE html>
-
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head runat="server">
- <title>Bootstrap Multiselect</title>
- <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" />
- <link rel="stylesheet" type="text/css" href="Style/bootstrap-multiselect.css" />
- <script src="Scripts/jquery-1.9.1.min.js"></script>
- </head>
- <body>
- <form id="form1" runat="server">
- <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
- <div class="container">
- <div class="row">
- <div class="col-md-12">
- <h3>Bootstrap MultiSelect Dropdownlist</h3>
- <asp:UpdatePanel ID="udpMain" runat="server">
- <ContentTemplate>
-
- <uc1:AutoCompleteDdl ID="ddlAutoComplete" runat="server" IncludeSelectAllOption="false"
- ButtonWidth="320px" SelectAllText="All" NonSelectedText="--Select Option--" MaxHeight="400"
- EnableFiltering="true" FilterPlaceholder="Search For Something..." SelectForm="Multiple"
- PlaceHolder="Select a Value" />
- <p>
- <asp:Button ID="btnGet" runat="server" Text="Get Data" OnClick="btnGet_Click" />
- </p>
- <p>
- <asp:Label ID="lblData" runat="server" />
- </p>
- </ContentTemplate>
- </asp:UpdatePanel>
- </div>
- </div>
- </div>
- </form>
- </body>
- </html>
Note:
- Here I’ve added the user control on my page.
- 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
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
-
- public partial class _Default : System.Web.UI.Page
- {
- List<SelectModel> lstData = new List<SelectModel>();
-
- protected void Page_Load(object sender, EventArgs e)
- {
- if (!IsPostBack)
- {
- for (int i = 0; i < 100; i++)
- {
- lstData.Add(new SelectModel() { Value = "Item " + i, Text = "Item " + i });
- }
- ddlAutoComplete.DataValueField = "Value";
- ddlAutoComplete.DataTextField = "Text";
-
- ddlAutoComplete.DataSource = lstData;
- }
- }
- protected void btnGet_Click(object sender, EventArgs e)
- {
- string value = ddlAutoComplete.Value;
- string text = ddlAutoComplete.Text;
-
- lblData.Text = "<b>Value: </b>" + value + "<br/><b>Text: </b>" + text;
-
- }
- }
Now just run the application and you’ll see the following output.
Select some items from the dropdownlist and you’ll find those selected items below our dropdownlist in an unordered list.
You may also try filtering the data by typing something in the “
Search For Something” textbox.
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.
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.