Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET Gridview with Row Drag and Drop using Jquery TableDnD

0.00/5 (No votes)
17 Sep 2014 1  
This article describes how to implement row drag and drop inside ASP.NET Gridview using Jquery TableDnD plugin and how to pass reordered sequence back to server

Introduction

ASP.NET Gridview by default does not provide a way to drag and drop rows. This can be achived using Jquery TableDnD plugin  https://github.com/isocra/TableDnD/tree/master/stable 

Background

While Jquery TableDnD plugin is fantastic way to allow end users to rearrange data in GridView the issue arise when that rearranged data needs to be sent back to server. As all the manipulation on the GridView is done using JavaScript server will not have a clue about rearranged data/rows.
This tip describes a way to overcome this issue so you can pass the reordered values back to the server and preserve the changes done by user on the client side.

Using the code

1.Create ASP.NET Web Application project in Visual Studio. First of all, we will create a DTO class to hold some data that we can display in a gridview. For this demo, I have created a DTO class of outstanding orders that contains some properties and some dummy data.

        //Some calss to hold data for gridview.
        [Serializable]
        public class Outstanding
        {
            public int SequenceId { get; set; }
            public int RecordId { get; set; }

            public string Item { get; set; }
            public string Order { get; set; }
            public int Line { get; set; }
            public int Status { get; set; }
            public string ToLocation { get; set; }
            public decimal Qty { get; set; }
            public DateTime RegDate { get; set; }
            public string Location { get; set; }
            public decimal AllocQty { get; set; }


            public List<outstanding> GetOutstanding()
            {
                List<outstanding> lstOrders = new List<outstanding>();

                lstOrders.Add(new Outstanding() { SequenceId=1, RecordId = 5000, Item = "CocaCola", Order = "000101", Line = 1, Status = 20, ToLocation = "Sydney", Qty = 2000, RegDate = new DateTime(2014, 1, 1), Location = "USA", AllocQty = 100 });
                lstOrders.Add(new Outstanding() { SequenceId = 3, RecordId = 5001,Item = "BubbleGum", Order = "000101", Line = 1, Status = 20, ToLocation = "Sydney", Qty = 2500, RegDate = new DateTime(2014, 1, 11), Location = "USA", AllocQty = 300 });
                lstOrders.Add(new Outstanding() { SequenceId = 4, RecordId = 5002, Item = "Coffee", Order = "000111", Line = 1, Status = 50, ToLocation = "Melbourne", Qty = 2500, RegDate = new DateTime(2014, 1, 10), Location = "USA", AllocQty = 100 });
                lstOrders.Add(new Outstanding() { SequenceId = 5, RecordId = 5003, Item = "Sugar", Order = "000112", Line = 1, Status = 50, ToLocation = "Melbourne", Qty = 2300, RegDate = new DateTime(2014, 1, 10), Location = "NZ", AllocQty = 300 });
                lstOrders.Add(new Outstanding() { SequenceId = 8, RecordId = 5004, Item = "Milk", Order = "000112", Line = 1, Status = 50, ToLocation = "Melbourne", Qty = 2300, RegDate = new DateTime(2014, 1, 10), Location = "NZ", AllocQty = 200 });
                lstOrders.Add(new Outstanding() { SequenceId = 9, RecordId = 5005, Item = "Green Tea", Order = "000112", Line = 1, Status = 20, ToLocation = "Melbourne", Qty = 300, RegDate = new DateTime(2014, 1, 10), Location = "NZ", AllocQty = 220 });
                lstOrders.Add(new Outstanding() { SequenceId = 10, RecordId = 5006, Item = "Biscuit", Order = "000131", Line = 1, Status = 70, ToLocation = "Perth", Qty = 200, RegDate = new DateTime(2014, 1, 12), Location = "IND", AllocQty = 10 });
                lstOrders.Add(new Outstanding() { SequenceId = 11, RecordId = 5007, Item = "Wrap", Order = "000131", Line = 1, Status = 20, ToLocation = "Perth", Qty = 2100, RegDate = new DateTime(2014, 1, 12), Location = "IND", AllocQty = 110 });
                return lstOrders;
            }
        }

2.In Default.aspx page in the header section add a reference to JavaScript libraries Jquery and TableDnD plugin

 <script src="Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
 <script src="Scripts/jquery.tablednd.js" type="text/javascript"></script>
 

3. Add a Grdiview to the Default.aspx page inside an UpdatePanle and create BoundColumns to display Outstanding Order data.

 <asp:UpdatePanel ID="upnlOutstanding" runat="server" ChildrenAsTriggers="true" UpdateMode="Conditional">

                    <ContentTemplate>

                        <h4>

                            Outstanding Orders</h4>

                                               <asp:GridView ID="grdViewOutstanding" runat="server" AutoGenerateColumns="False"

                            BackColor="White" BorderColor="#999999" BorderStyle="Solid" CellPadding="5" ForeColor="Black"

                            GridLines="Both" AllowPaging="True" CellSpacing="1" EmptyDataText="No outstanding orders found"

                            CssClass="Grid" PageSize="10" AllowSorting="true" OnPageIndexChanging="grdViewOutstanding_PageIndexChanging"

                             >

                            <FooterStyle BackColor="#CCCCCC" />

                            <Columns>

                                <asp:BoundField DataField="SequenceId" HeaderText="SequenceId"  />

                                <asp:BoundField DataField="Item" HeaderText="Item" />

                                <asp:BoundField DataField="Order" HeaderText="Order" />

                                <asp:BoundField DataField="Line" HeaderText="Line" />

                                <asp:BoundField DataField="Status" HeaderText="Status" />

                                <asp:BoundField DataField="ToLocation" HeaderText="ToLocation" />

                                <asp:BoundField DataField="Qty" HeaderText="Qty" />

                                <asp:BoundField DataField="RegDate" HeaderText="RegDate" DataFormatString="{0:dd/MM/yyyy}" />

                                <asp:BoundField DataField="Location" HeaderText="Location" />

                                <asp:BoundField DataField="AllocQty" HeaderText="AllocQty" />

                                <asp:BoundField DataField="RecordId" HeaderText="RecordId" />

                            </Columns>

                            <PagerStyle HorizontalAlign="Center" CssClass="pgr" />

                            <SelectedRowStyle BackColor="#000099" Font-Bold="True" ForeColor="White" />

                            </asp:GridView>

                    </ContentTemplate>

                </asp:UpdatePanel>

4.Now in the Page_Load event, we will bind gridview to the dummy data. I have kept data in ViewState for this demo.

         protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                Outstanding objOutstanding = new Outstanding();
                List<outstanding> lstOutstandingOrders = new List<outstanding>();
                lstOutstandingOrders = objOutstanding.GetOutstanding();
                grdViewOutstanding.DataSource = lstOutstandingOrders;
                grdViewOutstanding.DataBind();

                ViewState["lstOutstandingOrders"] = lstOutstandingOrders;
                upnlOutstanding.Update();
            }
        }

5.In the Default.aspx page add two hidden fields ( For the purpose of the demo I have made these input fields as text fields so you can view what is going on with the fields. To hide the fields from display change its type from text to hidden). These fields will be used to track which rows are being dragged and the new sequence number for the items. As there is no direct way to let server know that row order for GridView has changed theses two fields will keep a track of changes and that information will be passed to the server on postback.

 <label for="eleNewSeq">New Sequence </label> <input id="eleNewSeq"  runat="server" style="width:100%" type="text" value="" />
 <label for="eleDragged">Record Dragged </label>  <input id="eleDragged"  runat="server" style="width:100%" type="text" value="" />
 

6.Now add a script tag in Default.aspx page and apply tableDnD to the GridView in document ready jquery function $(); When you start dragging the row it will apply "DragTableRow" css class to the row that is being dragged. As you can notice there is a onDrop function which will get called when you drop the row. In this function we get the row that was being dragged and get the value of RecordId from it. This value is than gets added to the two hidden fields. I have used ":" as a seperator for fields so I can use one input element to keep track of all the recordIds that are being resequenced. You can call an Ajax function here and update the server instantly but to prevent multiple calls to the serve I have added a button to the Default.aspx page and on its click all the information will go back to the server and application will do the resequencing of data.


 
               $(document).ready(function () {
                $("#<%= grdViewOutstanding.ClientID %>").tableDnD({
                    onDragClass: "DragTableRow",
                    onDrop: function (table, row) {

                        var rows = table.tBodies[0].rows, newOrder = '', dragged = '';
                        dragged = $('#<%= eleDragged.ClientID %>').val();
                        dragged += row.cells[10].innerText == undefined ? row.cells[10].textContent : row.cells[10].innerText + ":";
                        for (var i = 1; i < rows.length; i++) {
                            newOrder += rows[i].cells[10].innerText == undefined ? rows[i].cells[10].textContent : rows[i].cells[10].innerText + ":";
                        }
                        $('#<%= eleNewSeq.ClientID %>').val(newOrder);
                        $('#<%= eleDragged.ClientID %>').val(dragged);
                    }
                });
            });
 

7.Add logic to do the resounding on the server on "Update Order Sequence" button's click event


     protected void btnUpdateOrderSequence_Click(object sender, EventArgs e)
        {
            int recordId = 0;
            int seq = 0;
            Dictionary<int, int=""> recordIdSeq = new Dictionary<int, int="">();
            List<int> recordIds = new List<int>();
            List<int> sequences = new List<int>();
         
            foreach (GridViewRow row in grdViewOutstanding.Rows)
            {
                seq = int.Parse(row.Cells[0].Text.Trim());
                sequences.Add(seq); // List of Sequence Id
            }

            if (!string.IsNullOrEmpty(eleNewSeq.Value)) // New Sequenced RecordIds
            {
                string[] allNewOrderdRecordId = eleNewSeq.Value.Trim().Split(':'); // Get New Order of Record Ids
                for (int i = 0; i < allNewOrderdRecordId.Length; i++)
                {
                    if (int.TryParse(allNewOrderdRecordId[i], out recordId))
                    {
                        recordIds.Add(recordId);
                    }
                }
            }
            if (recordIds.Count > 0)
            {
                sequences.Sort();
                for (int i = 0; i < recordIds.Count; i++)
                {
                    recordIdSeq.Add(recordIds[i], sequences[i]); //Setup new order -> Which sequenceId is assinged to which Record
                }
            }
            //For the purpose of this demo this manipulation is done on the viewstate data. Ideally you may want to save the new sequencing in the database and rebind gridview
             if (ViewState["lstOutstandingOrders"] != null)
             {
                List<outstanding> lstOutstandingOrders = (List<outstanding>)ViewState["lstOutstandingOrders"];
                List<outstanding> lstOutStandingResequenced = new List<outstanding>();
                int i = 0;
                foreach (Outstanding objTemp in lstOutstandingOrders)
                {
                    objTemp.SequenceId = recordIdSeq[objTemp.RecordId];  // Assign New Sequence Id 
                    i++;
                    lstOutStandingResequenced.Add(objTemp);
                }
                if (lstOutStandingResequenced.Count > 0)
                {
                    lstOutStandingResequenced = lstOutStandingResequenced.OrderBy(x => x.SequenceId).ToList();
                    ViewState["lstOutstandingOrders"] = lstOutStandingResequenced;
                    grdViewOutstanding.DataSource = lstOutStandingResequenced;
                    grdViewOutstanding.DataBind();
                    upnlOutstanding.Update();
                }

            }


          

        }

Points of Interest

This is one way of passing re-sequenced GridView rows back to the server.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here