Monday, April 27, 2009

AJAX ReorderList Example for Adding and Editing Items using the EntityDataSource

This blog entry is very similar to my entry AJAX ReorderList Example for Adding and Editing Items using the SqlDataSource. I highly recommend you read it first to understand the fixes and enhancements I made, since it is the same logic for the EntityDataSource I show here. The functionality is the same, but the difference is that this example show how to use the EntityDataSource (part of the ADO.NET Entity Framework) instead of the SqlDataSource.

The code is very similar to what I did for the SqlDataSource. However, there is some changes that needed to be done as well. The biggest one is that the ReorderList when used with the EntityDataSource requires a DataBind() call after all commands except Edit and Update, and requires special logic for the Update command.

The big change is that there is now a RequiresReorderListDataBind Boolean that I added. This flag is set to true on the initial page load, and then set based on the command that is executed. In turn, when the control is rendered, if RequiresReorderListDataBind is true then DataBind() is called in the PreRender event. You could also call the DataBind() in the appropriate command events such as OnInsertCommand, OnDeleteCommand. However, the Update command needs to call the UpdateItem() and then call DataBind() earlier in the cycle so we put it in the OnItemCommand event. Also, you can’t but the DataBind() call in OnItemCommand for the Insert and Delete. For this reason, I have the logic in the particular events that I do. I wanted to put everything in the OnItemCommand event, but it didn’t work. :(

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]

You will need to add a ADO.NET Entity Data Model (just like you add any other file to your web site). Select the database and table you created above. I called my Model MyModel and my entities MyEntities.

Here is the contents of the .aspx file.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="EntityDataSourceTest.aspx.cs" Inherits="EntityDataSourceTest" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>

<%@ Register assembly="System.Web.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" namespace="System.Web.UI.WebControls" tagprefix="asp" %>

<!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="entityDSItems"
                ItemInsertLocation="End"
                onitemreorder="ReorderList1_ItemReorder"
                onitemcommand="ReorderList1_ItemCommand"
                onprerender="ReorderList1_PreRender"
                ShowInsertItem="True">
                <ItemTemplate>
                    &nbsp;
                    <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 %>">
                        &nbsp;
                    </asp:Panel>   
                </DragHandleTemplate>
                <ReorderTemplate>
                    <div style="width: 300px; height: 20px; border: dotted 2px black;">
                        &nbsp;
                    </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>
        </div>
        <asp:EntityDataSource ID="entityDSItems" runat="server"
            ConnectionString="name=MyEntities"
            ContextTypeName="MyModel.MyEntities"
            DefaultContainerName="MyEntities"
            EnableDelete="True"
            EnableInsert="True"
            EnableUpdate="True"
            EntitySetName="TestTable1"
            EntityTypeFilter="TestTable1"
            OrderBy="it.intOrder ASC"
            StoreOriginalValuesInViewState="False">
        </asp:EntityDataSource>
    </form>
</body>
</html>

Here is the code-behind (.cs) file.

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;

public partial class EntityDataSourceTest : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Label3.Text = DateTime.Now.ToLongTimeString();
        if (!IsPostBack)
        {
            ShowDragHandle = true;
            RequiresReorderListDataBind = false;
        }
    }
     
    protected void ReorderList1_ItemReorder(object sender, AjaxControlToolkit.ReorderListItemReorderEventArgs e)
    {
        ShowDragHandle = true;
    }

    protected Boolean ShowDragHandle { get; set; }

    protected void ReorderList1_ItemCommand(object sender, AjaxControlToolkit.ReorderListCommandEventArgs e)
    {

        switch (e.CommandName)
        {
            case "Edit":
                ShowDragHandle = false;
                RequiresReorderListDataBind = false;
                break;

            case "Update":
                ShowDragHandle = true;
                ReorderList1.UpdateItem(ReorderList1.EditItemIndex);
                ReorderList1.DataBind();
                RequiresReorderListDataBind = false;
                break;

            // Cancel, Insert, Delete, and any unknown case
            default:
                ShowDragHandle = true;
                RequiresReorderListDataBind = true;
                break;
        }
    }
   
  
    private Boolean RequiresReorderListDataBind { get; set; }
    protected void ReorderList1_PreRender(object sender, EventArgs e)
    {
        if (RequiresReorderListDataBind)
        {
            ReorderList1.DataBind();
        }
    }
}

Tips

  • Be sure to set the ContextType property of the EntityDataSource as described here.
  • There are fewer issues when using a SqlDataSource as described here.
  • Be sure to set the OrderBy property of your EntityDataSource. An example is “it.intOrder ASC”.

2 comments:

Unknown said...

Hi! do you have any idea how can i use two of this reorderlist?? with the same tabke data??

Brent V said...

Hi hen,

What problem are you seeing? I am assuming you are trying to keep them in sync with eachother. I would recommend using the same datasource for starters. Then you may try disabling the viewstate so that they always are required on postback. That may have side-effects thoughts. In any event, you will need to databind again on each list.

Give me more info, and perhaps I can give more specific advise.

Brent