The AJAX Control Toolkit has some very powerful controls in it. The ReorderList is no exception. It basically allows users to drag and drop rows of the list around into any order the user desired. It also, allows the user to edit and add new rows as well.
It does support the SqlDataSource quite well. This blog entry will show how to use the SqlDataSource. However, it seems that does not support the EntityDataSource that well. In a later blog entry I will show how to use the EntityDataSource.
The ReorderList has some undesired behavior such as being able to reorder items when one of the rows is in Edit mode. This “feature” allows the following problem that shows when the items are reordered, after the postback, the same position (EditItemIndex) is the same which means if the item you were editing has a different position, another row (now in that same EditItemIndex) will be edited, not the row you were editing. I show you how to change (fix) this behavior.
Most examples you find out there, except one that I can find don’t show how to do Edit on the list of items. This blog shows a pretty good implementation of using the SqlDataSource, so I would recommend looking here also. This is where I started and what my examples are based on. The only issue I found with his example is that after an reorder, edit will edit the wrong row. To fix this be sure to do the key extra steps.
There are some key extra steps you need to do to get Editing of the Reorder list to work, that you don’t necessarily have to do for the read only mode.
- PostBackOnReorder=”True”
- Don’t use the Update panel around the ReorderList (you can, but it won’t do any good).
This example assumes you have a table in your database. Here is the SQL you can use to create one.
CREATE TABLE [dbo].[TestTable1](
[intID] [int] IDENTITY(1,1) NOT NULL,
[strName] [varchar](50) NOT NULL,
[strLink] [varchar](50) NOT NULL,
[intOrder] [int] NOT NULL,
CONSTRAINT [PK_TestTable1] PRIMARY KEY CLUSTERED
(
[intID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
This is an enhanced copy of the blog I noted earlier.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>OrderedList AJAX</title>
<style type="text/css">
.ajaxOrderedList li
{
list-style:none;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" ScriptMode="Release" />
<div class="ajaxOrderedList">
<ajaxToolkit:ReorderList ID="ReorderList1" runat="server"
AllowReorder="True"
PostBackOnReorder="True"
SortOrderField="intOrder"
DataKeyField="intID"
DataSourceID="sqlDSItems"
ItemInsertLocation="End"
onitemreorder="ReorderList1_ItemReorder"
onitemcommand="ReorderList1_ItemCommand">
<ItemTemplate>
<asp:HyperLink ID="HyperLink1" runat="server" Text='<% #Eval("strName") %>' NavigateUrl='<%# Eval("strLink") %>' />
<asp:LinkButton ID="LinkButton1" runat="server" CommandName="Edit" Text="Edit" />
<asp:LinkButton ID="LinkButton3" runat="server" CommandName="Delete" Text="Delete" />
</ItemTemplate>
<DragHandleTemplate>
<asp:Panel ID="dragHandle" runat="server"
style="height: 20px; width: 20px; border: solid 1px black; background-color: Red; cursor: pointer;"
Visible="<%# ShowDragHandle %>">
</asp:Panel>
</DragHandleTemplate>
<ReorderTemplate>
<div style="width: 300px; height: 20px; border: dotted 2px black;">
</div>
</ReorderTemplate>
<InsertItemTemplate>
<asp:Label ID="Label1" runat="server" Text="Name"></asp:Label>
<asp:TextBox ID="txtName" runat="server" Text='<%# Bind("strName") %>'></asp:TextBox><br />
<asp:Label ID="Label2" runat="server" Text="Link"></asp:Label>
<asp:TextBox ID="txtLink" runat="server" Text='<%# Bind("strLink") %>'></asp:TextBox><br />
<asp:Button ID="btnInsert" runat="server" Text="Add Link" CommandName="Insert" />
</InsertItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtName" runat="server" Text='<%# Bind("strName") %>'/>
<asp:TextBox ID="txtLink" runat="server" Text='<%# Bind("strLink") %>' />
<asp:TextBox ID="txtOrder" runat="server" Text='<%# Bind("intOrder") %>' />
<asp:LinkButton ID="LinkButton1" runat="server" CommandName="Update" Text="Update" />
<asp:LinkButton ID="LinkButton2" runat="server" CommandName="Cancel" Text="Cancel" />
</EditItemTemplate>
</ajaxToolkit:ReorderList>
<asp:Label ID="Label3" runat="server" Text="Label"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Button" />
</div>
<asp:SqlDataSource ID="sqlDSItems" runat="server" ConnectionString="<%$ ConnectionStrings:MyConnectionString %>"
SelectCommand="SELECT [intID], [strName], [strLink], [intOrder] FROM [TestTable1] ORDER BY [intOrder]"
DeleteCommand="DELETE FROM [TestTable1] WHERE [intID] = @intID"
InsertCommand="INSERT INTO [TestTable1] ([strName], [strLink], [intOrder]) VALUES (@strName, @strLink, @intOrder)"
UpdateCommand="UPDATE [TestTable1] SET [strName] = @strName, [strLink] = @strLink, [intOrder] = @intOrder WHERE [intID] = @intID">
<DeleteParameters>
<asp:Parameter Name="intID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="strName" Type="String" />
<asp:Parameter Name="strLink" Type="String" />
<asp:Parameter Name="intOrder" Type="Int32" />
<asp:Parameter Name="intID" Type="Int32" />
</UpdateParameters>
<InsertParameters>
<asp:Parameter Name="strName" Type="String" />
<asp:Parameter Name="strLink" Type="String" />
<asp:Parameter Name="intOrder" Type="Int32" />
</InsertParameters>
</asp:SqlDataSource>
</form>
</body>
</html>
I do however need some code-behind because I am using events to fix some of the issues I described above. Here is the code-behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using AjaxControlToolkit;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Label3.Text = DateTime.Now.ToLongTimeString();
if (!IsPostBack)
{
ShowDragHandle = true;
}
}
protected void ReorderList1_ItemReorder(object sender, ReorderListItemReorderEventArgs e)
{
ShowDragHandle = true;
}
protected Boolean ShowDragHandle { get; set; }
protected void ReorderList1_ItemCommand(object sender, ReorderListCommandEventArgs e)
{
switch (e.CommandName)
{
case "Cancel":
case "Insert":
case "Delete":
case "Update":
ShowDragHandle = true;
break;
case "Edit":
ShowDragHandle = false;
break;
default:
break;
}
}
}
The code is pretty straight forward I think, but here is a bit of explanation to help you understand. The ShowDragHandle boolean is bound to the Panel that makes up the drag handle. It shows and hides based on this boolean. When the page if first loaded (non-postback), it is shown. All events except Edit set the ShowDragHandle to true.
I do have a Label called Label3 that is set to the current data-time on page load. This is there so that you can see when a postback occurs. No real reason to include this in your solution, it is really just to help see when a postback occurs.
Tips
- Be sure that your select statement has an order by statement and is ordering by (ASCENDING) the same column you set the SortOrderField to.
- If you need more information on installing the AJAX Control Toolkit in Visual Studio 2008 SP1, check of my blog entry.