Click here to Skip to main content
12,403,391 members (71,536 online)
Click here to Skip to main content
Add your own
alternative version

Stats

138.7K views
6.7K downloads
61 bookmarked
Posted

ASP.NET Combobox dropdownlist with Images

, 1 Oct 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
An ASP.NET combobox dropdownlist with images, Internet Explorer/Firefox/Opera compatible
Static mode DropdownlistImage

drop.JPG

Dynamic mode DropdownlistImage with dynamic databinding

drop.JPG

Introduction

It's very difficult to find a free and compatible (with all browsers) dropdownlist that can contain image and text. However, I looked at the jQuery open source components and saw that jQuery developers have done an excellent work with their several widgets that they have developed. jQuery is a powerful JavaScript framework with very beautiful and optimized widgets.

I found an example of their dropdownlist image in a simple HTML page, and I decided to try to create a scalable HTML control that encapsulates this dropdownlist. The URL of the simple example is http://marghoobsuleman.com/jquery-image-dropdown.

Using the Code

The base component is a very simple basic HtmlSelect (System.Web.UI.Htmlcontrols namespace). I extended this class to add the specific behaviour.

At the beginning, I added the resources of the component in the assembly (JavaScript files, CSS file, and the arrow image of my extended HtmlSelect class). I added these resources on the override of the PreRender method, and I added the references in the AssemblyInfo.cs file. Here is the Microsoft recommendation for that. All these resources must be "embedded resources".

The following code shows you a special case: how to display a picture embedded in an assembly and call it in CSS code. In the beginning, the arrow image of the HtmlSelect is referenced in dd.css like this:

.dd .ddTitle span.arrow 
{ 
  float:right; 
  display:inline-block; 
  width:16px; 
  height:16px; 
  cursor:pointer;
  background-image:url('arrow_d.gif');
}

ASP.NET is not able to display arrow_d.gif with this declaration, because the URL of the picture is not arrow_d.gif. If you want to display this picture, you must follow three steps:

Step 1: You must get the image URL with the GetWebResourceUrl method of the ClientScript object like this:

//get url of embedded image
string urlImageArrowCombo = Page.ClientScript.GetWebResourceUrl(this.GetType(), 
                            "AssemblyName.dd_arrow.gif");

(In this example, the picture is at the root of the assembly). If the picture was in an assembly directory called "toto", "AssemblyName.dd_arrow.gif" would become "AssemblyName.toto.dd_arrow.gif".

Step 2: Extract the CSS code of the CSS file and put it in the server side to inject the image URL in the style:

string urlImageArrowCombo = 
   Page.ClientScript.GetWebResourceUrl(this.GetType(), "ComboImg.dd_arrow.gif");

StringBuilder strStyleArrow = new StringBuilder();

strStyleArrow.Append(" .dd .ddTitle span.arrow { ")
   .Append(" float:right; ")
   .Append(" display:inline-block; ")
   .Append(" width:16px; ")
   .Append(" height:16px; ")
   .Append(" cursor:pointer; ")
   .Append(" background-image:url('" + urlImageArrowCombo + "');")
.Append(" } ");

HtmlGenericControl styleArrow = new HtmlGenericControl("style");
styleArrow.Attributes.Add("type", "text/css");

jqdd.Controls.Add(
    new LiteralControl(strStyleArrow.ToString())
);

Page.Header.Controls.Add(styleArrow);

Last step: If there are lots of HtmlSelect images in the same page, the style that you add in the header of the page must be shared by all HtmlSelect image controls. So, the test Page.Items.Contains("styleAlreadyPut")) is necessary, to add the style once. The OnPreRender event is to add resources like I just explained. Here is the code:

/// Test if the Script manager is not missing
/// for the Sys.WebForms.PageRequestManager manipulation in prerender event
/// and load script and css
protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender(e);

    if (!this.DesignMode)
    {
        // Test for ScriptManager and register if it exists
        // we need it for PageRequestManager manipulation in prerender
        ScriptManager sm = ScriptManager.GetCurrent(Page);

        if (sm == null)
            throw new HttpException("A ScriptManager control " + 
                                    "must exist on the current page.");

        //Add js and css files resource
        string cssdd = Page.ClientScript.GetWebResourceUrl(GetType(), 
                            "ComboImg.dd.css");
        string scriptJQuery = Page.ClientScript.GetWebResourceUrl(this.GetType(), 
                                   "ComboImg.jquery-1.3.2.min.js");
        string scriptJQuerydd = Page.ClientScript.GetWebResourceUrl(this.GetType(), 
                                   "ComboImg.jquery.dd.js");

        HtmlLink lnk = new HtmlLink();
        lnk.Href = cssdd;
        lnk.Attributes["rel"] = "stylesheet";
        lnk.Attributes["type"] = "text/css";

        HtmlGenericControl jq = new HtmlGenericControl("script");
        jq.Attributes.Add("language", "JavaScript");
        jq.Attributes.Add("type", "text/javascript");
        jq.Attributes.Add("src", scriptJQuery);
        jq.Attributes.Add("alt", "scriptJQuery");

        HtmlGenericControl jqdd = new HtmlGenericControl("script");
        jqdd.Attributes.Add("language", "JavaScript");
        jqdd.Attributes.Add("type", "text/javascript");
        jqdd.Attributes.Add("src", scriptJQuerydd);
        jqdd.Attributes.Add("alt", "scriptJQuerydd");

        Page.Header.Controls.Add(jq);
        Page.Header.Controls.Add(jqdd);
        Page.Header.Controls.Add(lnk);

        //Put one time the style whose gives reference to arrow of the combo
        if (!Page.Items.Contains("styleAlreadyPut"))
        {
            //get url of embedded image
            string urlImageArrowCombo = Page.ClientScript.GetWebResourceUrl
					(this.GetType(), "ComboImg.dd_arrow.gif");

            StringBuilder strStyleArrow = new StringBuilder();

            strStyleArrow.Append(" .dd .ddTitle span.arrow { ")
               .Append(" float:right; ")
               .Append(" display:inline-block; ")
               .Append(" width:16px; ")
               .Append(" height:16px; ")
               .Append(" cursor:pointer; ")
               .Append(" background-image:url('" + urlImageArrowCombo + "');")
           .Append(" } ");

            HtmlGenericControl styleArrow = new HtmlGenericControl("style");
            styleArrow.Attributes.Add("type", "text/css");

            jqdd.Controls.Add(
                new LiteralControl(strStyleArrow.ToString())
            );

            Page.Header.Controls.Add(styleArrow);

            Page.Items.Add("styleAlreadyPut", "styleAlreadyPut");
        }
    }
}

I overrode the OnDataBinding method because the base OnDataBinding of the HtmlSelect does a specific treatment only if DataValueField and DataTextField are defined. (Watch the source code of OnDataBinding with Reflector (it's your best friend Smile | :) ).)

In our case, we don't use these properties because we don't need them and we need to create a ListItem with the values of the bound DataTable. The final point to see is the currentValue property which allows to save the currently selected value before the databinding, to retrieve it afterwards.

///Redefine OnDataBinding of the select
///without DataTextfiled and Datamember properties
protected override void OnDataBinding(EventArgs e)
{
    IEnumerable data = base.GetData();
    currentValue = Value;

    if (data != null)
    {
        DataTable source = ((DataView)data).Table;
        base.Items.Clear();
        ICollection is2 = data as ICollection;
        if (is2 != null)
        {
            this.Items.Capacity = is2.Count;
        }

        foreach (DataRow dr in source.Rows)
        {
            string value = FormatString(dr[0]);
            string imgPath = FormatString(dr[1]);
            string text = FormatString(dr[2]);
            
            ListItem it = new ListItem();
            it.Enabled = true;
            it.Text = text;
            it.Value = value;
            it.Selected = (value.Equals(currentValue));

            base.Items.Add(it);
        }
    }
    Value = currentValue;
    this.ViewState["_!DataBound"] = true;
    this.RequiresDataBinding = false;
}

Using Reflector, I looked at the implementation of the RenderChildren method of the HtmlSelect class. In my case, I made two distinctions:

  • Without data-binding: call the RenderChildren base class.
  • With data-binding: override the RenderChildren implementation to generate option tags with the correct format.

The correct format is "item text".

The conclusion is that if you want to databind this combo, you must provides a DataTable with three columns:

  1. item value
  2. image path
  3. the text of the item

Here is the RenderChildren implementation:

/// Generates options tags
protected override void RenderChildren(HtmlTextWriter writer)
{
    if (DataSource != null)
    {
        if (DataSource.GetType() == typeof(DataTable))
        {
            DataTable source = (DataTable)DataSource;

            if (source.Rows.Count == 0)
            {
                base.RenderChildren(writer);
                return;
            }

            foreach (DataRow dr in source.Rows)
            {
                string value = FormatString(dr[0]);
                string imgPath = FormatString(dr[1]);
                string text = FormatString(dr[2]);
                bool selected = currentValue.Equals(value);

                if (selected)
                    writer.Write("" + text + "");
                else
                {
                    writer.Write("" + text + "");
                }
                writer.WriteLine();
            }
        }
    }
    else
    {
        base.RenderChildren(writer);
    }
}

RenderControl adds a script which allows the initialization of the dropdownlist with the powerful jQuery framework. To initialize the dropdownlist, you must execute the following jQuery statements: $(document).ready(function() { $('#dropdownlistId').msDropDown(); }. But, ASP.NET will encounter JavaScript errors during the loading phase if you execute only these statements.

Arnold Matusz is a jQuery ASP.NET developer, and his solution to use JQuery with ASP.NET is available here. The solution is simple: execute this script at the end of the Request AJAX event.

/// Set the jQuery script for the combo at the beginning of the page request
public override void RenderControl(HtmlTextWriter writer)
{
    base.RenderControl(writer);
    
    StringBuilder scriptInit = new StringBuilder();

    scriptInit.Append(" <script type="\"text/javascript\""> ")
     .Append(" Sys.WebForms.PageRequestManager.getInstance()" + 
             ".add_endRequest(EndRequestHandler); ")
     .Append("    function EndRequestHandler(sender, args) { ")
     .Append("       if (args.get_error() == undefined) { ")
     .Append("            setImageComBo_" + this.ID + "(); ")
     .Append("       }  ")
     .Append("     } ")
     .Append("   function setImageComBo_"+this.ID+"() { ")
     .Append("       $(document).ready(function() { ")
     .Append("               $('#"+this.ID +"').msDropDown();                       ")
     .Append("       });  ")
     .Append("   }  ")
     .Append("   setImageComBo_" + this.ID + "();    ")
     .Append("</script>

Points of Interest

I learned to encapsulate a jQuery component within ASP.NET. I invite you to try developing more jQuery ASP.NET web controls; they are very useful and beautiful...

I look forward to your suggestions.

History

  • 28th September, 2009: Initial post
  • 29th September, 2009: Updated source code

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

David Zenou
Software Developer Several
France France
Fan of .NET Technologies
Go to see my blog : http://davidzenou.blogspot.com/2009/01/david.html

You may also be interested in...

Comments and Discussions

 
PraiseThanks Pin
ezequielsd18-Feb-16 1:58
memberezequielsd18-Feb-16 1:58 
QuestionFor an updated version of the dropdown Pin
Dewey4-Oct-13 4:51
memberDewey4-Oct-13 4:51 
QuestionWhere is source code for postback functionality? Pin
SkippingAdi3-Mar-11 4:34
memberSkippingAdi3-Mar-11 4:34 
GeneralWidth Problem With Safari Pin
manofatlantic1-Dec-10 7:04
membermanofatlantic1-Dec-10 7:04 
Generalsharepoint Pin
rangagmail3-Nov-10 21:34
memberrangagmail3-Nov-10 21:34 
GeneralRe: sharepoint Pin
David Zenou3-Nov-10 23:47
memberDavid Zenou3-Nov-10 23:47 
GeneralProblems with master page Pin
Member 189730328-Oct-10 22:31
memberMember 189730328-Oct-10 22:31 
GeneralPerformance Pin
maha.mahathy3-Sep-10 23:59
membermaha.mahathy3-Sep-10 23:59 
GeneralThanks for the nice article Pin
Madhanlal JM4-Aug-10 17:40
memberMadhanlal JM4-Aug-10 17:40 
GeneralReset Issue. Pin
Viral Upadhyay28-Jun-10 22:30
memberViral Upadhyay28-Jun-10 22:30 
GeneralRight Arrow Not Showing [modified] Pin
manofatlantic15-Jun-10 5:16
membermanofatlantic15-Jun-10 5:16 
GeneralRe: Right Arrow Not Showing Pin
manofatlantic15-Jun-10 8:00
membermanofatlantic15-Jun-10 8:00 
GeneralServer.Transfer on dropdown selection Pin
kynatic6-Jun-10 1:54
memberkynatic6-Jun-10 1:54 
GeneralGood one! Pin
Sandeep Mewara27-Mar-10 5:21
memberSandeep Mewara27-Mar-10 5:21 
GeneralOnChange problem Pin
Member 15586132-Feb-10 5:51
memberMember 15586132-Feb-10 5:51 
Generalgood job Pin
Arlen Navasartian18-Jan-10 21:06
memberArlen Navasartian18-Jan-10 21:06 
Questionhow to set "dropdownlist selected" property in page load [modified] Pin
Anusha Kumar7-Jan-10 10:12
memberAnusha Kumar7-Jan-10 10:12 
AnswerRe: how to set "dropdownlist selected" property in page load Pin
David Zenou7-Jan-10 13:36
memberDavid Zenou7-Jan-10 13:36 
GeneralRe: how to set "dropdownlist selected" property in page load [modified] Pin
Anusha Kumar8-Jan-10 9:01
memberAnusha Kumar8-Jan-10 9:01 
QuestionModalPopupExtender Issue Pin
Member 176675627-Nov-09 2:17
memberMember 176675627-Nov-09 2:17 
QuestionData not displaying in DropDownList Pin
Ajatshatru25-Nov-09 19:40
memberAjatshatru25-Nov-09 19:40 
AnswerRe: Data not displaying in DropDownList Pin
David Zenou25-Nov-09 21:17
memberDavid Zenou25-Nov-09 21:17 
QuestionRe: Data not displaying in DropDownList Pin
Ajatshatru25-Nov-09 21:56
memberAjatshatru25-Nov-09 21:56 
QuestionThe control doesn't postback? Pin
rayprestige22-Oct-09 15:52
memberrayprestige22-Oct-09 15:52 
AnswerRe: The control doesn't postback? [modified] Pin
David Zenou24-Oct-09 13:49
memberDavid Zenou24-Oct-09 13:49 
GeneralRe: The control doesn't postback? Pin
rayprestige26-Oct-09 16:07
memberrayprestige26-Oct-09 16:07 
GeneralRe: The control doesn't postback? Pin
Ter@Byte28-Oct-09 1:58
memberTer@Byte28-Oct-09 1:58 
GeneralRe: The control doesn't postback? Pin
rayprestige3-Nov-09 9:36
memberrayprestige3-Nov-09 9:36 
GeneralRe: The control doesn't postback? Pin
David Zenou3-Nov-09 14:14
memberDavid Zenou3-Nov-09 14:14 
GeneralRe: The control doesn't postback? Pin
David Zenou9-Nov-09 13:07
memberDavid Zenou9-Nov-09 13:07 
GeneralRe: The control doesn't postback? Pin
Caezar Girang9-Sep-10 15:46
memberCaezar Girang9-Sep-10 15:46 
GeneralRe: The control doesn't postback? Pin
Member 189730330-Oct-10 23:20
memberMember 189730330-Oct-10 23:20 
GeneralRe: The control doesn't postback? Pin
Suren Mkrtchyan5-Feb-11 9:33
memberSuren Mkrtchyan5-Feb-11 9:33 
GeneralRe: The control doesn't postback? Pin
gablu2u17-Aug-11 4:19
membergablu2u17-Aug-11 4:19 
GeneralControl in UserControl Pin
jkarnofsky20-Oct-09 9:43
memberjkarnofsky20-Oct-09 9:43 
GeneralRe: Control in UserControl Pin
kevin b jenkins21-Oct-09 9:26
memberkevin b jenkins21-Oct-09 9:26 
GeneralRe: Control in UserControl Pin
David Zenou24-Oct-09 8:15
memberDavid Zenou24-Oct-09 8:15 
GeneralNo dropdown icon Pin
Member 35573746-Oct-09 4:12
memberMember 35573746-Oct-09 4:12 
GeneralRe: No dropdown icon Pin
David Zenou7-Oct-09 7:20
memberDavid Zenou7-Oct-09 7:20 
GeneralCode Updated Pin
David Zenou1-Oct-09 23:10
memberDavid Zenou1-Oct-09 23:10 
GeneralI can't update my code Pin
David Zenou29-Sep-09 5:56
memberDavid Zenou29-Sep-09 5:56 
GeneralRenderControl - Minor Bug Pin
Member 73795628-Sep-09 23:14
memberMember 73795628-Sep-09 23:14 
GeneralRe: RenderControl - Minor Bug Pin
David Zenou29-Sep-09 3:30
memberDavid Zenou29-Sep-09 3:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160721.1 | Last Updated 1 Oct 2009
Article Copyright 2009 by David Zenou
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid