Reddnet Scribbles

It makes me want to gouge my eyes out with a cheese grater!

AjaxControlToolkit - Using the ReorderList with simple collections

Stephen M. Redd
Saturday, March 29 2008

Download Sample Project

Recently I've been working with the AjaxControlToolkit and Microsoft's Ajax technologies in .net 3.5. While I love the AjaxToolkit, I find the documentation and code-sample is somewhat lacking.

The ReorderList is also one of the lest intuitive controls in the Toolkit.

There are several other samples around the net, but all the ones I found assumed your were binding to a DataSource control of some sort, and most didn't demonstrate persisting changes to an underlying data store.

The few that showed persistence assumed a SqlDataSoruce control that would automate persistence with two-way binding (outside of demo-land, this is a a rare case  in my experience).

So when I first tried out this control, I was surprised at how difficult it was to use it with a simple collection such as an array, or a generic list.

Here is the basic markup you need in your page:

<ajaxToolkit:ReorderList ID="OrderList" runat="server" AllowReorder="true"
            LayoutType="Table" OnItemReorder="OrderList_ItemReorder" 
            PostBackOnReorder="true">
            <ItemTemplate>
                <span style="cursor: pointer;">
                    <asp:Label ID="ItemName" runat="server" 
                               Text='<%# Container.DataItem %>' />
                </span>
    </ItemTemplate>
</ajaxToolkit:ReorderList>

We're setting the text of the label control to the Container.DataItem directly rather than using an Eval or Bind method. That's because simple collections don't have properties that Eval and Bind can use, so you put the content of the data item directly in your output. This is the same with almost all bindable controls with simple collections, but is also one of those things the documentation just sort of "assumes" you already know... which is probably why I coded asp.net for about 4 years before I discovered this little trick.

On a postback or callback, there is no reliable way to get at the data items in their re-arranged state. If you put a button on the page to postback to the server and try to look at the items in the control, you will only be able to see them in the order they had been in when the control was first bound to the collection.

This means you can't just let the user make changes on the client and just submit the page back when they are done. The only reliable way to keep up with the user made reordering is to let the control postback each time the user makes a change, then manually keep track of the changes yourself.

Annoyingly, if you let the control post back to the server as the users makes their changes, the control will re-render itself with the original items in their original order. This will cause the list to reset after each postback effectively undoing the user's changes.

The only way around that seems to be to manually rebind the control yourself on each postback after you've updated the collection that you are using to manually track the changes.

To get all this to work together, the trick is to cache a copy of the items. When a user reorders the list you rearrange your copy of the items, recache it, and re-bind the ReorderList control to your updated copy.

How you choose to cache the items might depend on how much information is in the collection. For small collections you can just use ViewState, but for larger collections you'd probably want to cache them on the server with the Cache API or session variable.

This example will use ViewState since it assumes small and simple collection.

Here is the code that does all this:

private string[] OrderItems
{
    get
    {
        //We assume the array of items will be small, so we use viewstate
        //  If the array were big you may need to use session, the cache 
// API,
or even a database or filesystem to store the items
// between postbacks.
object items = ViewState["OrderItems"]; if(items == null) // items are not in viewstate, read from data store { items = GetOrderItemsFromDb(); //get values from the data store ViewState["OrderItems"] = items;//shove into viewstate } return (string[])items; } set { ViewState["OrderItems"] = value; } } private string[] GetOrderItemsFromDb() { //dummy up items, instead of a real DB
string[] ret = new string[] { "Item 1", "Item 2", "Item 3" };
return ret; } protected void Page_Load(object sender, EventArgs e) { Message.Text = string.Empty; } protected void Page_PreRender(object sender, EventArgs e) { // doing this at PreRender so we don't have to worry about when/if // we should bind based on if it's a postback or callback and what not. OrderList.DataSource = OrderItems; OrderList.DataBind(); } protected void SaveOrder_Click(object sender, EventArgs e) { //normally you'd save to reordered list to the DB or whatever foreach(string s in OrderItems) { // output the re-ordered values to page
Message.Text = Message.Text + s + "<br />";
} } protected void OrderList_ItemReorder(object sender, ReorderListItemReorderEventArgs e) { string[] items = OrderItems; List<string> list = new List<string>(OrderItems); //using a list for the reordering (convienience) string itemToMove = list[e.OldIndex]; list.Remove(itemToMove); list.Insert(e.NewIndex, itemToMove); OrderItems = list.ToArray(); //you could save this to the DB now, but this example uses a
//save button to batch up changes
}

As you can see, this is pretty straight forward. We maintain our own copy of the items collection putting it into ViewState between server trip. When the user makes a change the event handler just syncs our copy of the items collection. On PreRender we rebind the ReorderList to our collection, which should always be in sync with the client's copy. And finally, the save button can just commit the changes using our copy.

Stephen M. Redd
Saturday, March 29 2008
Filed under: Code
Tagged as: , , ,
24 Comments

» Trackbacks & Pingbacks

    No trackbacks yet.
Trackback link for this post:
http://reddnet.net/trackback.ashx?id=205

» Comments

  1. Craig Howard avatar

    Nice !

    Craig Howard — April 19, 2008 9:23 AM
  2. Adam avatar

    Hi - Just wanted to let you know that this was a big help. I am surprised that the control itself doesn't maintain state through viewstate by default.

    I wish MS had better documentation on this stuff. All I could find was the ReorderList sample on the asp.net ajax website, with an incomplete list of properties and methods.

    Thanks again!

    Adam — July 16, 2008 4:17 PM
  3. Jeff avatar

    Outstanding. Very helpful. Hard to believe there wasn't an to make the original reorder list this simple and useful.

    Jeff — July 20, 2008 10:04 AM
  4. Kevin McKinney avatar

    What about edit and inserting, have you found a way to accomplish those bits of functionality while using this technique. I can't seem to figure it out.

    Kevin McKinney — August 1, 2008 11:37 AM
  5. Stephen M. Redd avatar

    If you want a good comprehensive example, you can grab the source for my TicketDesk application. The admin section has a settings editor with three reorder lists that implement delete, update, insert, and reorder operations.

    You can download TicketDesk from:

    http://codeplex.com/TicketDesk

    Stephen M. Redd — August 1, 2008 12:36 PM
  6. John avatar

    Good Article on a very clunky control..

    John — October 23, 2008 12:26 PM
  7. Tom-Erik Thorbeck avatar

    I was having the same issues as you when using this control for the first time. On top of that I just a got a new home with no internet yet.

    Frustrating to say the least.

    Thanks for the tip!

    Tom-Erik Thorbeck — November 26, 2008 10:35 AM
  8. The Master avatar

    Thanks man, after many searches through useless other posts, this one really was what i was looking for.

    Cheers!

    The Master — January 3, 2009 6:27 PM
  9. inc avatar

    Thx man!

    Cheers

    inc — February 12, 2009 4:27 PM
  10. Jon S avatar

    Good work, I was just about to abandon this nasty control when i found your post.

    I tweaked it a little so i store only an array of Int as a lookup to items new positions, keeps the storage requirements down for session.

    I had issues with using ViewState, however i had PostBackOnReorder="false" instead, which may be the cause. The control mostly ignores this anyway and happily calls back and calls the event handler.

    If it wasn't for the nice dragging functionality and the time wasted working with this control i'd have abandoned it. I think i'm unlikely to use it again unless it's changed significantly.

    Thanks again !

    Jon S — February 27, 2009 2:38 PM
  11. ricky avatar

    very usefull, thanks!

    ricky — May 4, 2009 9:13 PM
  12. robert avatar

    Good Article, thanks a lot..

    robert — June 14, 2009 8:43 PM
  13. pradeep avatar

    Really a good article..helped me

    pradeep — June 18, 2009 7:06 AM
  14. online casino gambling directory of games avatar

    Thanks, mate. I've it working but still do not understand why previously, when I tried to do it myself got the exception: "...It's not a datasource and does not implement IList". Can you give some light on it?

    online casino gambling directory of games — June 27, 2009 6:26 AM
  15. FAbio avatar

    What about DELETE COMMAND?? I am not able to implement it, the function is never fired. I have added

    OnDeleteCommand="fTest"

    and

    Protected Sub fTest(ByVal sender As Object, ByVal e As AjaxControlToolkit.ReorderListCommandEventArgs)

    But the funciton never takes the control. Any ideas?

    FAbio — July 3, 2009 11:46 AM
  16. Dan  James avatar

    You champion.... I've wasted a day on this bloody control. I'm floored that a library with this much exposure is so poorly documented/tested/engineered for reliability. Really nice work making sense of it and thanks for the clear and concise post.

    Dan James — October 19, 2009 2:47 PM
  17. Mike avatar

    Check out the jquery sortable list - it can be much better and more flexible.

    <a href ="http://jqueryui.com/demos/sortable/">jquery sortable lists</a>

    Mike — November 6, 2009 2:48 AM
  18. Stephen M. Redd avatar

    Thanks mike, I'll check it out.

    I've long since lost all faith in the Ajax Control Toolkit and have discontinued using it in all of my projects. I do hope that Microsoft folds responsibility for the development of these kinds of controls into one of their core development teams in the future. Their core IDE and Tools team does a generally good job, and most of their out-of-band projects are also goo. But not so with the toolkit.

    Over the last two years, the toolkit has remained the single most frustrating set of UI components that I've ever encountered. Each version brings very little improvement, but frequently they introduce new bugs or inconsistencies that make an already unreliable toolset even more unstable.

    Stephen M. Redd — November 6, 2009 3:56 AM
  19. AeKaSaMo avatar

    Thanks for good sample

    AeKaSaMo — November 18, 2009 6:01 PM
  20. Bob avatar

    I run your code but can't drag the items ?!.

    Seems not to be working. I'm running IE 8.

    Bob — December 5, 2009 7:57 PM
  21. about oes tsetnoc avatar

    I have surfed the net more than three hours today, yet I never found any interesting article like yours. It's worth enough for me. Thanks.

    about oes tsetnoc — December 6, 2009 8:36 AM
  22. Bob avatar

    Update on the issue: not able to drag items around:

    I have tried tons of codes from around the Net without luck. Tried several editions of the Ajax toolkit etc. Ended up clicking the COMPATIBILITY VIEW in IE 8 and VUPTI: the shit works. Spend so much time on this issue. Not good enough Microsoft.

    Thanks by the way for a great article Stephen.

    Bob — December 6, 2009 1:40 PM
  23. Stephen M. Redd avatar

    No problem, but like I said before, the AjaxControlToolkit has disappointed me consistently to the point where I no longer use it.

    JQuery offer much more, and most of the JQuery plug-ins are much more reliable by far. They are a little harder to deal with at design time, but once you get the hang of it you save a lot of time by not having to troubleshoot and hack-around bugs and issues in the toolkit.

    I also invested in the DeveloperExpress suite of components for use in webforms projects. The DevX components give a really good design-time experience in visual studio, and they are decently reliable. The suite also covers most of the advanced control stuff I need. When I need something not offered in the DevX components though (or for my open source projects) I fall back on JQuery.

    Stephen M. Redd — December 10, 2009 6:18 AM
  24. Rick Liddle avatar

    After banging my head and pulling my hair out over worthless examples for two days, I found this and it helped tremendously. Thank you for taking the time to document your experience so that the rest of us can benefit from it.

    Based on your last comment, I think I'm going to take a look at the jQuery sortable list and see how that goes. I could less heartburn.

    Thanks again.

    Rick Liddle — February 24, 2010 2:58 PM

» Leave a Comment