Click here to Skip to main content
Click here to Skip to main content
Go to top

PickList

, 9 Jun 2004
Rate this:
Please Sign up or sign in to vote.
Two listboxes to choose from and client-side scripting to move items from left to right and vice versa

Introduction

When working with internet-programs, you should reduce the number of post backs to the server to a minimum. This is an often heard sentence. When I was working on a site where I had a lot of these picklists on screen (see screenshot above) which can move items from the left to the right listbox and vice versa. I was in a hurry and didn't want to listen to the message of this sentence. So I made a user-control and some necessary events to be hooked upon in my code-behind. You can imagine that the client response was not so great. Now that I have more time to think it over, I came up with this custom control with client-side scripting that should have worked perfect for that site. But alas, the site is up-and-running so think of this as some fun to please you and me.

Using the code

Picklist is a composite control, which consists of two ListBoxes and four HtmlInputButtons. I tried to name everything as common as possible. So, there is no 'Selected'-listbox or a 'DeSelectAll'-function but a left- and right listbox. I used HtmlInputButtons for these can easilly have JavaScript connected to it.

The class PickList is inherited from webcontrol. It implements the INamingContainer and IPostBackDataHandler. I choose for the WebControl and not for the Control class because it has some webcontrol properties like Height and Width for the layout of the listboxes. The INamingContainer makes the naming of multiple picklists on a webform unique. The first PickList gets a name like PickList1, the second one gets PickList2. The IPostBackDataHandler is nessecary for getting values back out of some hidden fields which are being filled by JavaScript on the client. Getting values back on the server is done in the LoadPostData method. Through the PostCollection collection, the posted-back-values can be retrieved. It seems to me that this collection contains the same as the Page.Request.Forms collection.

The working of PickList is that you fill the listboxes with whatever you want during design-time or in code. When rendering the control to html, it saves the items from the listboxes separated with <tab>'s to viewstate which is done in the Page_Load method. This way, we know what was originally in the listboxes when we get a postback. Next, in the OnPreRender function, we render two hiddenfields to the client, which are later being filled by JavaScript on the client. In the beginning when making this control, I used two HtmlInputHidden controls for storing values. I had to create these two controls in the CreateChildControls, set there ID's and values and then add these to the controls collection. After searching the internet I coincidentally found the Page.RegisterHiddenField function which works the Microsoft way and is used now, instead of the HtmlInputHidden controls. Since this function, there is no need for setting the values and add it to the controls-collection. Ironically, the work saved, is not significant.

protected override void OnPreRender(EventArgs e)
{ 
    base.OnPreRender(e);
        if (Page != null)
    {
        Page.RegisterHiddenField(HelperLeftID, this.ValuesLeft);
        Page.RegisterHiddenField(HelperRightID, this.ValuesRight);
    };
}

On the client, the JavaScript moves the items from one listbox to the other when the user clicks a HtmlInputButton. After this move, it sorts the collection whenever the IsSorted property is set to true. Hereafter, another JavaScript function will copy the items in the listboxes, separated with <tab>'s, to the two hiddenfields which are being read on the server when a postback takes place.

When the postback take place, the two hidden fields contain the new values for the listboxes. In the IPostBackDataHandler.LoadPostData method, the values are being read from the postCollection and compared to the saved viewstate. When changed, the items are stored in the item-collection of the listboxes. The new viewstate value's can also be saved here, but it better be saved in the Page_Load method. It seems that the collection has to be read again in the Page_Load, and it does. So why do this twice? Because the first time the control is created, the LoadPostData does not fire, but Page_Load will. ViewState has to be set for the control to work properly.

bool IPostBackDataHandler.LoadPostData(string postDataKey,
    System.Collections.Specialized.NameValueCollection postCollection)
{ 
    bool lblnReturn = false; 
    string NewLeftValue = postCollection[HelperLeftID]; 
    string NewRightValue = postCollection[HelperRightID];
    if (NewLeftValue != null) 
    { 
        EnsureChildControls(); 
        // If the user changes Input value, update the text property. 
        if (String.Compare(this.ValuesLeft, NewLeftValue) != 0) 
        { 
            this.ItemsLeft.Clear(); 
            foreach (string str in NewLeftValue.Split(strSep)) 
            { 
                if (str != string.Empty) 
                // Here ViewState could easilly be set 
                // Something like: this.ValuesLeft += str
                    this.ItemsLeft.Add(str); 
            }; 
            // Returning true invokes RaisePostDataChangedEvent. 
            lblnReturn = true; 
        } 
    }
    return lblnReturn;
}

Consider when calling Page.RegisterClientScriptBlock , always first call Page.IsClientSideScriptBlockRegistered , which will avoid the performance taking call to <CODE>Page.RegisterClientScriptBlock like this:

if (!Page.IsClientScriptBlockRegistered("PickListScript"))
        Page.RegisterClientScriptBlock("PickListScript", script);

This way, what is done in code behind for making the script is omitted.

In the source of the control, JavaScript is set in code-behind. I could have chosen for a separate js-file, but I choose for better deployment. Also, by reading the property IsSorted, the sort-function from the JavaScript can be switched off. When using a separate js-file should be some more coding.

Points of Interest

Databinding is not supported in this control because of simplicity. However, you can extent this control with databinding features from this good article http://www.codeproject.com/aspnet/webcontrolsdatabinding.asp. I have done it and it works great.

Also I thought it was difficult to implement child ListItems in the html-code like so:

<PickList id="PickList1">
    <LeftListBox ID="left1">
        <asp:ListItem Value="1">one</asp:ListItem>
            <asp:ListItem Value="1">one</asp:ListItem>
    </LeftListBox>
</PickList> 

The solution was found at http://blogs.aspadvice.com/jlovell/archive/2004/02/29/663.aspx. I should have entered the ParseChildren(true) and PersistChildrenattribute(false).

Also to view the ListBox in design-time properly, set the height and width property to something like 150px. I did not support a designer-class for design-time support. The look and feel in design-time comes directly from the Render method.

Hope you enjoyed it!

History

  • Version 1.0, June 2004.

License

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

Share

About the Author

Dries de Groot
Software Developer
Netherlands Netherlands
Hi my name is Dries de Groot. I have a Masters degree in applied physics and am graduated in solid-state matter. Besides that I am a .NET Professional with the following titles: MCAD, MCSD

Comments and Discussions

 
QuestionNeed to implement hierarchy in PickList control Pinmemberkgoyal19-Dec-11 11:44 
AnswerRe: Need to implement hierarchy in PickList control PinmemberDries de Groot23-Dec-11 3:27 
GeneralSmall fix for VB users PinmemberMyCodeProject200521-Aug-09 0:18 
GeneralNice! PinmemberJasonC7213-Oct-08 5:23 
QuestionFacing LIstBox Problem Pinmembersinhasourabh6-Jul-08 3:27 
GeneralUpdation in problem Pinmembersinhasourabh6-Jul-08 3:31 
GeneralTwo List Boxes in ASP.net using C# PinmemberManikkuttan10-Jun-08 19:18 
GeneralBUG Report PinmemberCDSGIO7312-Sep-07 0:03 
GeneralData mismatch after postback Pinmemberjyothiraj24-Jan-07 18:01 
GeneralMy component won't let me declare a LoadPostData Function Pinmemberhowardjr19-Dec-06 17:34 
GeneralRe: My component won't let me declare a LoadPostData Function PinmemberSebastian Streiger20-Dec-06 6:06 
GeneralRe: My component won't let me declare a LoadPostData Function Pinmemberhowardjr20-Dec-06 7:31 
GeneralRe: My component won't let me declare a LoadPostData Function PinmemberSebastian Streiger20-Dec-06 9:55 
GeneralRe: My component won't let me declare a LoadPostData Function Pinmemberhowardjr20-Dec-06 10:26 
GeneralRe: My component won't let me declare a LoadPostData Function PinmemberSebastian Streiger21-Dec-06 1:35 
GeneralRe: My component won't let me declare a LoadPostData Function Pinmemberhowardjr21-Dec-06 11:33 
Generaladd ondblclick Pinmemberxiezhenhua14-Nov-06 18:27 
GeneralRe: add ondblclick PinmemberDries de Groot18-Nov-06 9:18 
GeneralThanks for the article. PinmemberLakshmipathy21-Sep-06 20:15 
GeneralRe: Thanks for the article. PinmemberDries de Groot18-Nov-06 9:18 
QuestionHaving problem when used with master page Pinmemberjagamagge17-Aug-06 23:57 
AnswerRe: Having problem when used with master page PinmemberDries de Groot18-Nov-06 9:21 
GeneralStyle Attributes Pinmembergroovq27-Jul-06 19:53 
GeneralRe: Style Attributes PinmemberDries de Groot30-Aug-06 21:02 
QuestionHow Do i Add display text and values? Pinmemberpgarbutt9-Dec-05 10:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    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 | Mobile
Web02 | 2.8.140921.1 | Last Updated 10 Jun 2004
Article Copyright 2004 by Dries de Groot
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid