Introduction
The stock DropDown
control that comes with ASP.NET allows us to select only one item. To overcome this limitation, I wrote the MultiDropDown
ASP.NET Server Control that allows selection of multiple items from a checkable list of items. This control supports multiple instances in the same web page. The best part about this control is you do not have to add any other external files (like images, style sheets or JavaScript files) to your project, the control does everything automatically behind the scenes.
Features
- Supports multiple instances on the same page.
- Appearance of textbox, button, dropdown and tooltip can be customized.
- No external files like JavaScript or style sheets required. The control take care of everything.
- ASP.NET AJAX compliant. Works with
UpdatePanel
. - Uses plain JavaScript. No JavaScript framework (like jQuery, mootools, etc.) required.
- Works with Internet Explorer, Firefox, Chrome, Opera and Safari. (Safari and Chrome do not seem to honor the dropdown's
min-width
property though). - Just drag-n-drop to your page and start using the control.
- Allows searching items.
Background
I had been looking for a control that allows me to select multiple items from a drop down, after searching the Internet in vain to find one, I decided to write my own ASP.NET server control that allows selection of multiple items. The result? The MultiDropDown
control.
Using the MultiDropdown Control
The control consists of a textbox
, an image button and a dropdown. The default appearance of the control is:
Clicking on the textbox
or on the image button brings up the dropdown area.
When items are selected, the textbox
is automatically updated to show the comma separated list of the selected items. The selected rows are also highlighted. You can select items by clicking anywhere on the item and not just the checkbox
. You can also click the 'All' item to select/unselect all items in the dropdown. The control also has a built-in tooltip that automatically shows the selected items.
As you start typing in the Search box, the list is filtered to match all the items that start with the characters you type. Clicking on the Clear Search button clears the filter and display all items.
To use this control, add the MultiDropdown.dll to your Visual Studio toolbox and drag-n-drop the MultiDropdown
control. You can also add a reference to the assembly and create the control directive yourself. The control directive looks like this:
<%@ Register Assembly="MultiDropDown" Namespace="MultiDropDownLib"
TagPrefix="MultiDropDownLib" %>
And the control instance looks like this:
<MultiDrodownLib:MultiDrodown ID="MultiDropdown1" runat="server"/>
To add items to the control's dropdown, set its DataSource
, DataTextField
and DataValueField
properties.
DataTable dt1 = new DataTable();
dt1.Columns.Add(new DataColumn("Name", typeof(System.String)));
dt1.Columns.Add(new DataColumn("ID", typeof(System.String)));
dt1.Rows.Add(new string[] { "Apple" ,"1" });
dt1.Rows.Add(new string[] { "Orange" ,"2" });
dt1.Rows.Add(new string[] { "Pear" ,"3" });
dt1.Rows.Add(new string[] { "Banana" ,"4" });
dt1.Rows.Add(new string[] { "Grapes" ,"5" });
dt1.Rows.Add(new string[] { "Strawberry","6" });
MultiDropDown1.DataSource = dt1;
MultiDropdown1.DataTextField = "Name";
MultiDropdown1.DataValueField = "ID";
To get the list of selected items and selected values, use the SelectedItems
, SelectedValues
properties. The SelectedItems
property is comma separated and the SelectedValues
property is pipe separated.
string selectedItems = MultiDropdown1.SelectedItems;
string selectedValues = MultiDropdown1.SelectedValues;
Customizing the MultiDropDown Control
Almost every aspect of the control can be customized. Here's an instance of a customized control.
<MultiDropDownLib:MultiDropDown
ID="MultiDropDown2"
runat="server"
DropdownOnMouseOver="true"
DropdownOnFocus="true"
TextBoxClass="textbox1"
ImageButtonClass="imagebutton1"
TooltipClass="tooltip1"
DropdownClass="dropdown1"
/>
To show the dropdown just by hovering the mouse over the textbox
, set the DropdownOnMouseOver
property to true
. This is turned off by default to avoid unnecessary intrusion of the dropdown on the page. The DropDownOnFocus
property determines if the dropdown is shown when the textbox
receives focus. This property is true
by default.
The textbox
can be customized by setting the TextBoxClass
property to a custom CSS class.
.textbox1
{
border: 1px solid maroon;
background-color:#FFC2D0;
color:maroon;
font-weight:bold;
}
The button can be customized by setting the ImageButtonClass
property to a custom CSS class in your web project. The image is rendered as a div
element to enable images to be set with a CSS class. (The image
element does not allow images to be set with a CSS class.) To change the image to a custom image, set the background-image
property in your CSS class to the path of the desired image file path. Be sure to set the height
and width
properties also.
.imagebutton1
{
display:block;
background-image:url(../images/multidropdown.png);
background-position:bottom;
background-repeat:no-repeat;
height:18px;
width:21px;
}
The dropdown can be customized by setting the DropdownClass
property to a custom CSS class. However, when declaring a CSS class for the dropdown you have to declare separate classes for the td
as well, like this:
.dropdown1
{
border: 2px solid maroon;
min-width:150px;
}
.dropdown1 td
{
border: 1px dotted maroon;
background-color:#FFC2D0;
}
The tooltip's appearance can be customized by setting the TooltipClass
property to a custom CSS class.
.tooltip1 {
position:absolute;
display:block;
padding:2px 12px 3px 7px;
margin-left:5px;
background:#FFC2D0;
color:#222222;
border:4px solid maroon;
font-weight:bold;
}
Here's an example of a customized MultiDropDown
control:
Exploring the Source Code
The control is developed using Visual Studio 2010/.NET Framework 4.0. However, with little tweak it can be made to work with older versions of .NET. The project structure is like this:
The MultiDropDown.cs file contains the ASP.NET Server Control and it inherits from System.Web.UI.WebControls.WebControl
. It also implements the marker interface System.Web.UI.INamingContainer
to ensure that the ASP.NET runtime assigns unique names to the child controls based on the MultiDropDown
Control's Id. This helps us to write code in such a way that multiple instances of the control can be placed in the same ASP.NET Page. The control consists of a HTML Textbox
(HtmlInputText
), an HTML image (HtmlImage
), a div
element for the dropdown area (HtmlGenericControl
) and an ASP.NET GridView
control for the dropdown items and an Html table (HtmlTable
with associated HtmlTableRow
and HtmlTableCell
objects) to arrange the child controls. I decided to use the GridView
control instead of an HTML table to ease databinding.
The child controls are composed inside the control's class, this automatically takes care of the child control's ViewState
. The child controls are initialized in the overridden OnInit()
method. The CreateChildControls()
method is overridden to add the child controls to the server control's Controls collection and to do the actual databinding. The OnPreRender()
method is overridden to inject the link
tag for the stylesheet.
The JavaScript files, the Stylesheet and the default button images are embedded inside the control assembly as WebResource
s. This enables the control to serve embedded resources as resources over the web. You may wish to search CodeProject to learn how to use WebResources. I'll explain how the main JavaScript file is rendered as a <script>
tag in the page.
Right-click the file and select 'Properties' from the context menu and set 'Build Action' property to 'Embed Resource' in the properties window. Next, open AssemblyInfo.cs file and add this line:
[assembly: System.Web.UI.WebResource("MultiDropDownLib.js.multidropdown.js",
"text/javascript")]
where MultiDropDownLib
is the project name and /js is the folder structure and multidropdown.js is the actual file name. Make sure you specify the precise content type. You can then use the following code to inject the JavaScript file to the web page.
Page.ClientScript.RegisterClientScriptResource(this.GetType(),
"MultiDropDownLib.js.multidropdown.js")
The rendered script tag will look something like this:
<script src="http://www.codeproject.com/Test/WebResource.axd?
d=JA_U3mGno1O0AS_cetvr4oQvuwmDwmapV40Q5-daDigeJvW5b02MkDE-
6WzvJ1qzJcIRasEbn9S-0WWjgjLSCq7jY1MMtoQe_fVrDuMLxnMX_
Cp3ko0tZ6wmlon77boz5c3UXBvHxc0a2FZIGl-Xxw2&t=634450289371679687"
type="text/javascript"></script>
The other JavaScript files and the default button image are rendered in similar way.
The stylesheet is rendered using a similar technique by saving the css fie as a WebResource
. An HtmlLink
control is created and added to the Page's header using this code:
protected override void OnPreRender(EventArgs e) {
base.OnPreRender(e);
HtmlLink linkCSS = new HtmlLink();
linkCSS.Href = Page.ClientScript.GetWebResourceUrl(this.GetType(),
"MultiDropDownLib.css.multidropdown.css");
linkCSS.Attributes.Add("rel", "stylesheet");
linkCSS.Attributes.Add("type", "text/css");
Page.Header.Controls.Add(linkCSS);
}
The GridView
has three columns: A template column for the check box and two bound columns for the DataTextField
and DataValueField
properties.
- The checkboxes in the first column (and the
tr
elements themselves) have an onclick
event that checks/unchecks the row. - The second column holds the item's text and JavaScript uses this value to populated the textbox (
txtNameList
) with the comma separated list of items. The textbox's value is returned by the SelectedItems
property. - The third column that holds the item's value is hidden. The JavaScript uses this column to populate the hidden control (
hdnValueList
) with selected values. This hidden control is used to return the list of selected values through the SelectedValues
property.
Now coming to the JavaScripts, the main scripts to show/hide the dropdowns and check/uncheck items are in the multidropdown.js file. The functions ShowDropdown()
, HideDropdown()
, HideAllDropdowns()
, SelectRow()
(called from TR onclick
), SelectItem()
(called from Checkbox
's onclick), SelectAll()
do what their names suggest. A controlId
parameter is passed to them that specifies the instance of the control they're supposed to work on. This enables us to place more than one instance of the control on the same ASP.NET page. The Initialize()
function re-selects the selected items to restore state after a full postback or an AJAX partial postback. This function is called by code in the mddinitialize.js file. The full postback is handled by attaching the Initialize()
function to window.onload
event. The partial postback is handled by the predefined pageLoad(sender, args)
function. The mddtooltip.js file contains the tooltip class.
Points of Interest
A single instance of the tooltip class is reused to show tooltip for all the controls on a web page. This saves us some memory and system resources and keeps the DOM footprint smaller. You may be wondering why I did not have just one instance of the dropdown and reuse it across all controls in the page, the reason is that the tooltip class is simple, you just need to change the text and the CSS class to make it work with multiple instances, whereas the dropdown portion encapsulates a complete table and it is quite difficult to make it work with multiple instances. However, this is something that could be done in future, so I am adding this to the wishlist for the time being.
Wishlist
Features that could be implemented in future:
- Multi-column dropdown (e.g. Names of people with their address)
- Design-time support
- Dynamic resizing of the dropdown area using mouse
- Customize everything about the control (including dropdown background color, selected row color, etc.)
- A 'Debug' mode that displays the Value column in the dropdown and the values in the tooltip to enable troubleshooting in cases where the control does not behave as expected.
- One dropdown for all instances of the control in a web page. (Similar to tooltip class)
I hope you will enjoy using this control as much as I enjoyed developing it. Feel free to explore the source code and make changes as you wish. If you make any significant changes to the control, I would love to hear from you about the changes you made.
If you like this control and this article, then please vote for this article, you can find the vote button just below the author profile. Please send in your comments, suggestions, likes, dislikes or whatever; I want to hear from you.
History
Version 1.0
Version 2.0
- Search feature
- Minor bug fixes