ASP.NET has a very fine distinction between what happens on the server and what happens on the client. In fact, for the most part the two are very disconnected; and herein lies the problem. If you remember my last article, I told you that a Web control is simply a server-side component which renders HTML to the browser. Well, the standard ASP.NET ListBox control renders the only thing that can produce a ListBox in HTML, a <select>
tag. The <option>
tags within the <select>
tag are created using the contents of the Items
property in the ListBox control. The Items
property is filled at the server and its contents help build the proper HTML during rendering. This is very similar to a Textbox Web control rendering an <input>
tag and its Text
property mapping to the Value
attribute of the <input>
tag. Every time a page postback is triggered to the server, the ListBox control's Item
property is persisted to the ViewState
and rebuilt from the ViewState
just before the page re-renders.
collection property was never saved, to be reloaded at re-rendering. Instead the intent is to access the <option>
items in the rendered <select>
Remember I said that if the functionality occurs at the server side during postbacks, ViewState is saved and reloaded fine, keeping the Items
collection properly filled. But since your eventual goal is to perform this functionality on the client side, you are no longer properly adjusting the contents of the Items
property, and it is this property that you're depending on for state storage. Now you can see the dilemma. But don't worryI wouldn't be writing this article if I didn't have a solution. So let's take this one step at a time and start by developing the controls with the necessary client-side script code to perform the functionality each needs. Then I will teach you how to resynchronize it back with the server code.
The EnhancedListBox Control
In building the two controls, I will expand on concepts and ideas I taught you in the last couple of articles.
For the first control you'll add two things to the existing ASP.NET ListBox control. First you'll add a heading. Hey, why not? Most of the time you probably drop a label above a ListBox anyway, so you might as well build it in. Afterward you'll add two buttons to the ListBoxone to reorder up and the other down.
For brevity, I will omit all attribute decorations from all code snippets going forward.
Create a new class and make it inherit from the ListBox control like this:
public class EnhancedListBox : ListBox
If you compile this code as-is and add the control to your toolbox, you'll have a fully functional replica of the ASP.NET ListBox control with no differences whatsoever from the original. I chose to develop this control as an inherited control because I want it to be a drop-in replacement for the ASP.NET ListBox control. Later I'll add properties that will allow the visibility of the heading and/or the reorder buttons to be turned off and on. When they are all turned off, the control will appear and behave exactly as a regular ListBox control. However, you cannot add controls to it compositely using an override to CreateChildControls
because that's used to build a control hierarchy. The ASP.NET ListBox control was written as a Rendered Control and draws its entire HTML directly to the rendering engine so that is where you need to inject your stuff. You'll build the label and the two buttons using the Rendered Control approach, and render them by overriding the Render
method. However, the instant you override this method, you completely cancel out all rendering in the original ListBox, and that's unacceptable. So I'm going to do something a bit tricky.
My solution will draw this control as if I created it as a standard Rendered Control including table tags and the rendering of the label and buttons I'm adding. When I get to the part of the display rendering where I want to inject the original ListBox that I inherited from, I will call the base.Render
method. This will inject all the code that Microsoft wrote for the ListBox control into that section of HTML I am trying to draw (see Listing 1
). The properties listed in Table 1 determine appearance and behavior for this code. I won't list the property code in this article but you can see it all in the downloadable code. Note in the code that the buttons you are rendering are set to cause a postback based on the value of a property called ReorderButtonPostback
. The implementation of IPostBackEventHandler
will capture this postback.
Table 1: EnhancedListBox Properties
|Figure 1. EnhancedListBox Control: The EnhancedListBox control lets users reorder items within a list.|
Now that the control looks the way you want (Figure 1
), you can make the buttons do more than raise a postback. The finished product contains event handling code in the implementation of IPostBackEventHandler, as explained in my previous articles, so that events can be optionally raised to the server, in case a developer wants to execute further code at this point. But remember that you want to use these buttons to reorder the items in the ListBox and you want them to do it WITHOUT executing a postback. Now comes the fun part.