6

I'm trying to sort the records at a dataset according to users preference. I add a button (move up) to bump up the selected record 1 row higher and this is what i have done until now:

private void btnMoveUp_Click(object sender, EventArgs e)
{
    int index = dataGridView1.CurrentRow.Index;
    if (index >= 1) 
    { 
        var temp = dsWinners.Tables[0].Rows[index];
        dsWinners.Tables[0].Rows[index].Delete();
        dsWinners.Tables[0].Rows.InsertAt(temp, index - 1);
        dsWinners.Tables[0].AcceptChanges();
        dataGridView1.DataSource = dsWinners.Tables[0];
    }
}

but i get a error saying "This row already belongs to this table." at this line:

dsWinners.Tables[0].Rows.InsertAt(temp, index - 1);

i know that i have to use ImportRow(temp) instead of InsertAt(temp, index - 1) but the problem is i dont know how to import it at the right position. i have looked int to THIS but as the guy who answered the question says "Its sloppy and halfway."

is there anyway i can overcome this issue? and if yes, how can i do it?

Community
  • 1
  • 1
CodeMonkey
  • 2,511
  • 4
  • 27
  • 38
  • 1
    Try calling AcceptChanges after Delete and before you Insert in addition to one you have already – Adil Jun 11 '15 at 06:26
  • 1
    An alternative approach would be to add a Position-column to the table (if there is none yet) and initialize it with the position (1 ... n) at the beginning. Sort the view by this column. When the user wants to change a position you only have to swap the value of the cell in two rows and assert that the view is still sorted by this column. – Markus Jun 11 '15 at 06:27
  • @Adil i added AcceptChanges(); after delete and after insert. it removed the row, added a new row on the top of it but its empty!!! could it be because the temp is empty or it just doesnt add its content to the new row? – CodeMonkey Jun 11 '15 at 06:39
  • @Markus i dont have it since the table is not being pull from database...its a combination of generated form from excel and a 2d array. but can i add the column and keep it hidden? as in can i make the visible false? – CodeMonkey Jun 11 '15 at 06:42
  • I think @Markus approach is better. Have you tried swapping the Delete and InsertAt line in your approach and test the outcome? – Piyush Jun 11 '15 at 06:43
  • @P.K. yes ...i tried that as well but ill get the same error again. the "This row already belongs to this table." – CodeMonkey Jun 11 '15 at 06:46

4 Answers4

3

Instead of removing the row and adding it again at another position, you could add a column to the table that contains the position.

You'd not bind the DataGridView to the table itself but to a DataView that is sorted by the Position column.

In the DataGridView, you'd add all the columns except the Position so that the Position is not displayed.

When you move a row up or down, you swap the value of the Position cell with the previous or next row respectively. As the DataView is sorted by the position, the move is immediately reflected in the DataView.

The following console application shows the basic steps:

void Main()
{
    // Create a new DataTable
    DataTable tbl = GetData();
    // Add Position column and initialize it
    tbl.Columns.Add("Position", typeof(int));
    for(int i = 0; i < tbl.Rows.Count; i++) 
        tbl.Rows[i]["Position"] = i;
    PrintView("Original", tbl.DefaultView);

    // Create a view that is sorted by the Position column
    var view = new DataView(tbl);
    view.Sort = "Position";
    PrintView("Sorted", view); // No change as the rows are in original order anyway

    // Move a row
    SwapPositions(view, 0, 1); // Move first row down
    PrintView("Swapped", view);
}

private DataTable GetData()
{
    DataTable tbl = new DataTable();
    tbl.Columns.Add("Value", typeof(string));
    for(int i = 0; i < 3; i++)
        tbl.Rows.Add("Text " + i.ToString());
    return tbl;
}

private void PrintView(string header, DataView view)
{
    Console.WriteLine(header);
    foreach(DataRowView row in view)
        Console.WriteLine("{0}\t{1}", row["Position"], row["Value"]);
}

private void SwapPositions(DataView view, int rowIndex1, int rowIndex2)
{
    // Save rows as the change in the Position column is reflected immediately
    DataRowView row1 = view[rowIndex1];
    DataRowView row2 = view[rowIndex2];
    // Now swap positions
    var saveValue = row1["Position"];
    row1["Position"] = row2["Position"];
    row2["Position"] = saveValue;
    view.Table.AcceptChanges();
}

The output is:

Original
0  Text 0
1  Text 1
2  Text 2
Sorted
0  Text 0
1  Text 1
2  Text 2
Swapped
0  Text 1
1  Text 0
2  Text 2
Markus
  • 20,838
  • 4
  • 31
  • 55
1

Try below things :

var temp = dsWinners.Tables[0].Rows[index];         \\getting row
var newrow = dsWinners.Tables[0].NewRow();     \\ creating new row to insert
newrow.ItemArray = temp.ItemArray;            \\ copying data from old to new row
dsWinners.Tables[0].Rows[index].Delete(); \\deleting old row.
 dsWinners.Tables[0].Rows.InsertAt(newrow, index - 1); \\ adding new row.
Dreamweaver
  • 1,328
  • 11
  • 21
  • there is a problem with this code. it only move it up 1 row. – CodeMonkey Jun 11 '15 at 07:36
  • from your code I thought you want to do the same, but if all the rows need to be moved then the solution by Markus is a good approach.. but with slight modification, Instead of dealing at row level setting the filterexpression for datatable will do the task efficiently, http://stackoverflow.com/questions/9107916/sorting-rows-in-a-data-table to sort based on the column added. – Dreamweaver Jun 11 '15 at 07:50
0

You can try one more thing. Try replacing the code

var temp = dsWinners.Tables[0].Rows[index]; 

with the following::

var temp = dsWinners.Tables[0].NewRow();    
temp.ItemArray = dsWinners.Tables[0].ItemArray;

This is creating a new row and moving it to a given position instead of shifting an existing one.

Piyush
  • 830
  • 8
  • 19
0

This is for last index table move to first index in dataset:

        DataSet dsIndexchange = new DataSet();
        DataTable dtdummysummary = new DataTable();
        dtdummysummary = dsAssetInterval.Tables[dsAssetInterval.Tables.Count-1];

        dsAssetInterval.Tables.RemoveAt(dsAssetInterval.Tables.Count-1);
        dsIndexchange.Tables.Add(dtdummysummary);
        for (int i = 0; i < dsAssetInterval.Tables.Count; i++)
        {
            dsIndexchange.Tables.Add(dsAssetInterval.Tables[i].Copy());
        }
Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
Rajenthiran T
  • 77
  • 1
  • 6