Introduction
The ReorderList
is a very powerful piece of the ASP.NET AJAX Control Toolkit. It gives you the ability to interactively reorder a list of items.
The Problem
I put together this demonstration to go over how to wire the ASP.NET AJAX Toolkit’s ReorderList
control to a LINQ to SQL data source. Out of the box, the ReorderList
control gives you the ability to easily reorder items in a list on the client side. Where I found it fell short was in how the reordering changes that you make get committed back to the database.
The Solution
I created a fairly straightforward way to commit reordering changes back to the database at the time the reorder event takes place. In doing this, the reordering changes you make get committed to the database in real-time, as opposed to making a bunch of changes and clicking a Reorder button. I believe this is a much better way of doing it because there is a lower chance of changes getting lost, and this helps resolve contention issues in a multi-user reordering scenario.
The web page:
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="RealtimeReorderList.aspx.cs"
Inherits="RealtimeReorderlist.RealtimeReorderList" %>
<%@ 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 runat="server">
<link rel="Stylesheet" type="text/css"
href="ReorderList.css" />
<title>Realtime Reorderable List Using LINQ to SQL</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<fieldset>
<legend>Reorderable List Items</legend>
<div style="width: 850px">
<div class="reorderListDemo"
style="padding-bottom: 50px">
<ajaxToolkit:ReorderList ID="rlItemList"
DragHandleAlignment="Left"
PostBackOnReorder="true"
CallbackCssStyle="callbackStyle"
ItemInsertLocation="End"
ShowInsertItem="false"
runat="server">
<DragHandleTemplate>
<div class="dragHandle">
</div>
</DragHandleTemplate>
<ItemTemplate>
<div class="itemArea">
<span style="float: right">
<asp:Button Width="50" ID="Button3"
CommandName="Delete"
runat="server" Text="Delete" />
</span>
<asp:Label ID="ID" Visible="false"
runat="server"
Text='<%# Eval("ID") %>'></asp:Label>
<asp:Label ID="Order" Visible="false"
runat="server"
Text='<%# Eval("ListOrder") %>'></asp:Label>
<asp:Label ID="Name" runat="server"
Text='<%# Eval("Name") %>'></asp:Label>:
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("Description") %>'></asp:Label>
</div>
</ItemTemplate>
<ReorderTemplate>
<asp:Panel ID="Panel2" runat="server"
CssClass="reorderCue" />
</ReorderTemplate>
</ajaxToolkit:ReorderList>
</div>
</div>
</fieldset>
<fieldset>
<legend>Add List Item</legend>
<div>
<asp:TextBox ID="tbItemName"
runat="server"></asp:TextBox>
<ajaxToolkit:TextBoxWatermarkExtender ID="TBWE1"
runat="server" TargetControlID="tbItemName"
WatermarkText="Name"
WatermarkCssClass="watermarkTextBox" />
</div>
<div>
<asp:TextBox Rows="4" ID="tbItemDescription"
runat="server" Height="51px"
TextMode="MultiLine"></asp:TextBox>
<ajaxToolkit:TextBoxWatermarkExtender ID="TBWE2"
runat="server"
TargetControlID="tbItemDescription"
WatermarkText="Description"
WatermarkCssClass="watermarkTextBox" />
</div>
<div>
<asp:Button ID="btnAddReorderListItem"
runat="server" Text="Add"
OnClick="AddReorderListItem_Click" />
</div>
</fieldset>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
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 AjaxControlToolkit;
namespace RealtimeReorderlist
{
public partial class RealtimeReorderList : System.Web.UI.Page
{
protected int NewListOrderNumber;
protected List<reorderlistitem> ListDataItems;
protected void Page_Load(object sender, EventArgs e)
{
rlItemList.ItemReorder += new EventHandler<reorderlistitemreordereventargs>
(rlItemList_ItemReorder);
rlItemList.ItemCommand += new EventHandler<reorderlistcommandeventargs>
(rlItemList_ItemCommand);
GetListData();
if (!Page.IsPostBack)
BindData();
}
protected void rlItemList_ItemReorder(object sender,
ReorderListItemReorderEventArgs e)
{
var NewOrder = e.NewIndex + 1;
var OldOrder = e.OldIndex + 1;
var ReorderListItemID = Convert.ToInt32(((Label)(
e.Item.FindControl("ID"))).Text);
var db = new RealTimeReorderListDataDataContext();
var ListItemCount = 1;
var ListData = from ld in db.ReorderListItems
orderby ld.ListOrder
select ld;
foreach (var ListDataItem in ListData)
{
if (OldOrder > NewOrder
&& ListItemCount >= NewOrder
&& ListItemCount <= OldOrder
)
ListDataItem.ListOrder = ListItemCount + 1;
else if
(OldOrder < NewOrder
&& ListItemCount <= NewOrder
&& ListItemCount >= OldOrder
)
ListDataItem.ListOrder = ListItemCount - 1;
ListItemCount++;
if (ListDataItem.ID == ReorderListItemID)
ListDataItem.ListOrder = NewOrder;
}
db.SubmitChanges();
GetListData();
BindData();
}
void rlItemList_ItemCommand(object sender, ReorderListCommandEventArgs e)
{
if (e.CommandName != "Delete")
return;
var db = new RealTimeReorderListDataDataContext();
var ListData = from ld in db.ReorderListItems
where ld.ID == Convert.ToInt32(((Label)
(e.Item.FindControl("ID"))).Text)
select ld;
db.ReorderListItems.DeleteAllOnSubmit(ListData);
db.SubmitChanges();
GetListData();
BindData();
}
protected void AddReorderListItem_Click(object sender, EventArgs e)
{
GetListData();
var db = new RealTimeReorderListDataDataContext();
var RLI = new ReorderListItem
{
ListOrder = NewListOrderNumber,
Name = tbItemName.Text,
Description = tbItemDescription.Text
};
db.ReorderListItems.InsertOnSubmit(RLI);
db.SubmitChanges();
tbItemName.Text = "";
tbItemDescription.Text = "";
GetListData();
BindData();
}
protected void GetListData()
{
var db = new RealTimeReorderListDataDataContext();
var ListData = from ld in db.ReorderListItems
orderby ld.ListOrder
select ld;
ListDataItems = ListData.ToList();
NewListOrderNumber = ListDataItems.Count() + 1;
}
protected void BindData()
{
rlItemList.DataSource = ListDataItems;
rlItemList.DataBind();
}
}
}
The SQL schema:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ReorderList](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ListOrder] [int] NULL,
[Name] [nvarchar](256) NULL,
[Description] [nvarchar](4000) NULL,
CONSTRAINT [PK_ReorderList] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]