Sorting selected rows in DataGridView












4















I have a DataGridView in a Winforms application. I want to select a set of rows in it and sort those rows by a column (Timestamp)...



The rest of the rows should remain as they originally were..
Can this be done using the sort property of DGV



Thanks










share|improve this question























  • I can't think of any way that doesn't involve accessing the bound collection itself.

    – Ed Bayiates
    Jul 7 '11 at 20:37











  • Despite the accepted answer saying it can't be done using DGV's sort, it can be done using the sort variant that takes an IComparer. I've added a new answer to this old question showing how.

    – ToolmakerSteve
    Jan 1 at 21:45
















4















I have a DataGridView in a Winforms application. I want to select a set of rows in it and sort those rows by a column (Timestamp)...



The rest of the rows should remain as they originally were..
Can this be done using the sort property of DGV



Thanks










share|improve this question























  • I can't think of any way that doesn't involve accessing the bound collection itself.

    – Ed Bayiates
    Jul 7 '11 at 20:37











  • Despite the accepted answer saying it can't be done using DGV's sort, it can be done using the sort variant that takes an IComparer. I've added a new answer to this old question showing how.

    – ToolmakerSteve
    Jan 1 at 21:45














4












4








4


1






I have a DataGridView in a Winforms application. I want to select a set of rows in it and sort those rows by a column (Timestamp)...



The rest of the rows should remain as they originally were..
Can this be done using the sort property of DGV



Thanks










share|improve this question














I have a DataGridView in a Winforms application. I want to select a set of rows in it and sort those rows by a column (Timestamp)...



The rest of the rows should remain as they originally were..
Can this be done using the sort property of DGV



Thanks







c# sorting datagridview






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jul 7 '11 at 20:19









techmanctechmanc

153618




153618













  • I can't think of any way that doesn't involve accessing the bound collection itself.

    – Ed Bayiates
    Jul 7 '11 at 20:37











  • Despite the accepted answer saying it can't be done using DGV's sort, it can be done using the sort variant that takes an IComparer. I've added a new answer to this old question showing how.

    – ToolmakerSteve
    Jan 1 at 21:45



















  • I can't think of any way that doesn't involve accessing the bound collection itself.

    – Ed Bayiates
    Jul 7 '11 at 20:37











  • Despite the accepted answer saying it can't be done using DGV's sort, it can be done using the sort variant that takes an IComparer. I've added a new answer to this old question showing how.

    – ToolmakerSteve
    Jan 1 at 21:45

















I can't think of any way that doesn't involve accessing the bound collection itself.

– Ed Bayiates
Jul 7 '11 at 20:37





I can't think of any way that doesn't involve accessing the bound collection itself.

– Ed Bayiates
Jul 7 '11 at 20:37













Despite the accepted answer saying it can't be done using DGV's sort, it can be done using the sort variant that takes an IComparer. I've added a new answer to this old question showing how.

– ToolmakerSteve
Jan 1 at 21:45





Despite the accepted answer saying it can't be done using DGV's sort, it can be done using the sort variant that takes an IComparer. I've added a new answer to this old question showing how.

– ToolmakerSteve
Jan 1 at 21:45












4 Answers
4






active

oldest

votes


















3















Can this be done using the sort
property of DGV




No



The Sort method on the DataGridView is used for a bit more simple sorting. Such as Ascending or Descending sorting and the SortOrder property is also just for "simple" sorting.



Can this behavior be implemented? Sure.



I think the easiest way to do this, is this:




  • Store the index of the first selected item

  • Take out the items that you want to sort from the DataGridView

  • Sort the list using LINQ

  • Append the two lists and add the sorted list at the index stored in the first step.


However you need to think about how you want to handle if you selecte items that are not followed by each other, for instance if you select index { 1, 3, 6, 9 } you might stil lwant to append this to index 1.



Edit



Okay so I played around with this a little bit and came up with a way that you can implement this. It's not very optimized but you'll get the idea on how I meant.



First of all this is my SortSelectedIndices-method that I use:



static IEnumerable<T> SortSelectedIndices<T>(
IEnumerable<T> values,
IEnumerable<int> selectedIndices,
Func<IEnumerable<T>, IEnumerable<T>> sort)
{
var selectedValues = new List<T>();

for (var i = 0; i < selectedIndices.Count(); i++)
selectedValues.Add(values.ElementAt(selectedIndices.ElementAt(i)));

var sortedList = sort(selectedValues);

var finalList = new List<T>();

var startPositionFound = false;
for(var i = 0; i < values.Count(); i++)
{
if (selectedIndices.Contains(i))
{
if (startPositionFound) continue;

startPositionFound = true;
finalList.AddRange(sortedList);
}
else
finalList.Add(values.ElementAt(i));
}

return finalList;
}


Then I call it like this:



static void Main(string args)
{
var unsorted = new {3, 5, 6, 1, 2, 87, 432, 23, 46, 98, 44};
var selected = new {1, 4, 7};

Print(unsorted);

var sort = new Func<IEnumerable<int>, IEnumerable<int>>(
(x) => x.OrderBy(y => y).ToList());

var sorted = SortSelectedIndices(unsorted, selected, sort);

Print(sorted);
}


And this prints out the following:



{ 3,5,6,1,2,87,432,23,46,98,44 }
{ 3,2,5,23,6,1,87,432,46,98,44 }


I am just using a simple method here to print this out to the console:



static void Print<T>(IEnumerable<T> values)
{
Console.Write("{ ");
Console.Write(string.Join(",", values));
Console.WriteLine(" }");
}


So what you can do is to have a "sort"-button, when it's pressed you invoke SortSelectedIndices and then rebind the list when you're done. Remember I have not profiled or refactored this code, it might not be as fast as you like, I just want to give you an idea on what you can do to acheive the solution.






share|improve this answer


























  • How can this behavior be implemented?

    – techmanc
    Jul 7 '11 at 20:56











  • @techmanc, Did you try the steps that I wrote?

    – Filip Ekberg
    Jul 7 '11 at 20:58











  • @techmanc, I updated my answer with an example.

    – Filip Ekberg
    Jul 8 '11 at 8:33



















1














Based on Filips definition of the problem, and his example as the correct answer, my somewhat less general (no generics, no Func) solution would be this:



Public Function SortSelectedIndices(unsortedList As IEnumerable(Of Integer), selectedIndices As IEnumerable(Of Integer)) As IEnumerable(Of Integer)

If Not selectedIndices.Any() Then
Return unsortedList
End If

Dim extractedValues = From s In selectedIndices Select unsortedList(s)
Dim sortedExtractedValues = From e In extractedValues Order By e

Dim listWithoutExtractedValues = unsortedList.Except(extractedValues)
Dim resultList = New List(Of Integer)(listWithoutExtractedValues)

Dim firstSelectedIndex = Aggregate s In selectedIndices Order By s Into First()
resultList.InsertRange(firstSelectedIndex, sortedExtractedValues)

Return resultList

End Function


Edit: Filip just pointed out that the question is tagged "C#". But there is no mention of this in the text, so I deem it's not that important. I also assume that any reader familiar with .NET can translate "dim" to "var" and the likes, all by himself. :-P






share|improve this answer

































    0














    Definitely, the DataGridView cannot do this. So, the best solution would be to create a new collection (List), populate it with selected rows from the GridView and finally use its Sort method to order these rows. To sort data by a certain column, you can either write a custom IComparer class and pass it to the Sort method or use Linq:



    var orderedList = someList.OrderBy(obj => obj.TimeStampField);






    share|improve this answer































      0














      You can do any conceivable sort, directly in the DataGridView, by creating a custom IComparer, and passing it to DataGridView.Sort(IComparer). The trick is to figure out how to give that IComparer the needed info.

      See How to: Customize Sorting in the Windows Forms DataGridView Control / Custom Sorting Using the IComparer Interface , specifically class RowComparer : System.Collections.IComparer for details.



      In your case, we must

      a) associate each row with its original row number, and

      b) indicate whether or not a row participates in the sort.



      For the specific question, we want all the selected rows to stay after any rows before them, and before any rows after them. For example, if there are rows 0 - 9, and rows 3-7 are to be sorted, then rows 0-2 stay in their original order, as do rows 8 - 9. We can simplify the logic with a trick: assign the same row number to all the rows to be sorted, specifically the row number of the first such row. (3). Then when two rows have the same initial row number, sort on your sorting criteria.



      One way to add this "extra" information to each row, is to add a "hidden" column to each row.



      A second way is to put the information in a dictionary, and pass that in to your custom IComparer class.

      (Untested) code for this way:



      void SomeMethod()
      {
      DataGridView dgv = ...;

      // Iterate through the rows, building the dictionary.
      Dictionary<DataGridViewRow, int> rowToRowNumber = ...;
      int iFirstSelected = -1;
      for (int iRow = 0; iRow < dgv.Rows.Count; iRow++)
      {
      DataGridViewRow row = dgv.Rows[iRow];

      int iAdjusted = iRow;
      if (row.Selected)
      {
      if (iFirstSelected < 0)
      iFirstSelected = iRow;
      iAdjusted = iFirstSelected;
      }
      rowToRowNumber[row] = iAdjusted;
      }

      // Sort.
      dgv.Sort(new RowComparer(rowToRowNumber));
      }


      private class RowComparer : System.Collections.IComparer
      {
      // Values are the row numbers before the sort was done,
      // with all rows to sort set to the same value (the row number of the first row to sort).
      Dictionary<DataGridViewRow, int> _rowToRowNumber;

      public RowComparer(Dictionary<DataGridViewRow, int> rowToRowNumber)
      {
      _rowToRowNumber = rowToRowNumber;
      }

      public int Compare(object x, object y)
      {
      DataGridViewRow row1 = (DataGridViewRow)x;
      DataGridViewRow row2 = (DataGridViewRow)y;

      // Keep rows in order.
      int result = _rowToRowNumber(row1).CompareTo(_rowToRowNumber(row2));
      if (result != 0)
      return result;

      // Same row number, these are the rows to sort.
      return CustomCompare(row1, row2);
      }

      private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
      {
      // Replace with your custom logic.
      // TODO: If cells contain strings, may have to parse them into the
      // original data types, and compare those typed values rather than the cell values themselves.
      return row1.Cells[1].Value.CompareTo(row2.Cells[1].Value);
      }
      }


      NOTE: If the object from which a row was created is in row.Tag, then it may be preferable to retrieve those typed objects, and do the comparison on their properties:



          private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
      {
      MyClass ob1 = (MyClass)(row1.Tag);
      MyClass ob2 = (MyClass)(row2.Tag);
      return ob1.MyProp.CompareTo(ob2.MyProp);
      }





      share|improve this answer























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f6616633%2fsorting-selected-rows-in-datagridview%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        3















        Can this be done using the sort
        property of DGV




        No



        The Sort method on the DataGridView is used for a bit more simple sorting. Such as Ascending or Descending sorting and the SortOrder property is also just for "simple" sorting.



        Can this behavior be implemented? Sure.



        I think the easiest way to do this, is this:




        • Store the index of the first selected item

        • Take out the items that you want to sort from the DataGridView

        • Sort the list using LINQ

        • Append the two lists and add the sorted list at the index stored in the first step.


        However you need to think about how you want to handle if you selecte items that are not followed by each other, for instance if you select index { 1, 3, 6, 9 } you might stil lwant to append this to index 1.



        Edit



        Okay so I played around with this a little bit and came up with a way that you can implement this. It's not very optimized but you'll get the idea on how I meant.



        First of all this is my SortSelectedIndices-method that I use:



        static IEnumerable<T> SortSelectedIndices<T>(
        IEnumerable<T> values,
        IEnumerable<int> selectedIndices,
        Func<IEnumerable<T>, IEnumerable<T>> sort)
        {
        var selectedValues = new List<T>();

        for (var i = 0; i < selectedIndices.Count(); i++)
        selectedValues.Add(values.ElementAt(selectedIndices.ElementAt(i)));

        var sortedList = sort(selectedValues);

        var finalList = new List<T>();

        var startPositionFound = false;
        for(var i = 0; i < values.Count(); i++)
        {
        if (selectedIndices.Contains(i))
        {
        if (startPositionFound) continue;

        startPositionFound = true;
        finalList.AddRange(sortedList);
        }
        else
        finalList.Add(values.ElementAt(i));
        }

        return finalList;
        }


        Then I call it like this:



        static void Main(string args)
        {
        var unsorted = new {3, 5, 6, 1, 2, 87, 432, 23, 46, 98, 44};
        var selected = new {1, 4, 7};

        Print(unsorted);

        var sort = new Func<IEnumerable<int>, IEnumerable<int>>(
        (x) => x.OrderBy(y => y).ToList());

        var sorted = SortSelectedIndices(unsorted, selected, sort);

        Print(sorted);
        }


        And this prints out the following:



        { 3,5,6,1,2,87,432,23,46,98,44 }
        { 3,2,5,23,6,1,87,432,46,98,44 }


        I am just using a simple method here to print this out to the console:



        static void Print<T>(IEnumerable<T> values)
        {
        Console.Write("{ ");
        Console.Write(string.Join(",", values));
        Console.WriteLine(" }");
        }


        So what you can do is to have a "sort"-button, when it's pressed you invoke SortSelectedIndices and then rebind the list when you're done. Remember I have not profiled or refactored this code, it might not be as fast as you like, I just want to give you an idea on what you can do to acheive the solution.






        share|improve this answer


























        • How can this behavior be implemented?

          – techmanc
          Jul 7 '11 at 20:56











        • @techmanc, Did you try the steps that I wrote?

          – Filip Ekberg
          Jul 7 '11 at 20:58











        • @techmanc, I updated my answer with an example.

          – Filip Ekberg
          Jul 8 '11 at 8:33
















        3















        Can this be done using the sort
        property of DGV




        No



        The Sort method on the DataGridView is used for a bit more simple sorting. Such as Ascending or Descending sorting and the SortOrder property is also just for "simple" sorting.



        Can this behavior be implemented? Sure.



        I think the easiest way to do this, is this:




        • Store the index of the first selected item

        • Take out the items that you want to sort from the DataGridView

        • Sort the list using LINQ

        • Append the two lists and add the sorted list at the index stored in the first step.


        However you need to think about how you want to handle if you selecte items that are not followed by each other, for instance if you select index { 1, 3, 6, 9 } you might stil lwant to append this to index 1.



        Edit



        Okay so I played around with this a little bit and came up with a way that you can implement this. It's not very optimized but you'll get the idea on how I meant.



        First of all this is my SortSelectedIndices-method that I use:



        static IEnumerable<T> SortSelectedIndices<T>(
        IEnumerable<T> values,
        IEnumerable<int> selectedIndices,
        Func<IEnumerable<T>, IEnumerable<T>> sort)
        {
        var selectedValues = new List<T>();

        for (var i = 0; i < selectedIndices.Count(); i++)
        selectedValues.Add(values.ElementAt(selectedIndices.ElementAt(i)));

        var sortedList = sort(selectedValues);

        var finalList = new List<T>();

        var startPositionFound = false;
        for(var i = 0; i < values.Count(); i++)
        {
        if (selectedIndices.Contains(i))
        {
        if (startPositionFound) continue;

        startPositionFound = true;
        finalList.AddRange(sortedList);
        }
        else
        finalList.Add(values.ElementAt(i));
        }

        return finalList;
        }


        Then I call it like this:



        static void Main(string args)
        {
        var unsorted = new {3, 5, 6, 1, 2, 87, 432, 23, 46, 98, 44};
        var selected = new {1, 4, 7};

        Print(unsorted);

        var sort = new Func<IEnumerable<int>, IEnumerable<int>>(
        (x) => x.OrderBy(y => y).ToList());

        var sorted = SortSelectedIndices(unsorted, selected, sort);

        Print(sorted);
        }


        And this prints out the following:



        { 3,5,6,1,2,87,432,23,46,98,44 }
        { 3,2,5,23,6,1,87,432,46,98,44 }


        I am just using a simple method here to print this out to the console:



        static void Print<T>(IEnumerable<T> values)
        {
        Console.Write("{ ");
        Console.Write(string.Join(",", values));
        Console.WriteLine(" }");
        }


        So what you can do is to have a "sort"-button, when it's pressed you invoke SortSelectedIndices and then rebind the list when you're done. Remember I have not profiled or refactored this code, it might not be as fast as you like, I just want to give you an idea on what you can do to acheive the solution.






        share|improve this answer


























        • How can this behavior be implemented?

          – techmanc
          Jul 7 '11 at 20:56











        • @techmanc, Did you try the steps that I wrote?

          – Filip Ekberg
          Jul 7 '11 at 20:58











        • @techmanc, I updated my answer with an example.

          – Filip Ekberg
          Jul 8 '11 at 8:33














        3












        3








        3








        Can this be done using the sort
        property of DGV




        No



        The Sort method on the DataGridView is used for a bit more simple sorting. Such as Ascending or Descending sorting and the SortOrder property is also just for "simple" sorting.



        Can this behavior be implemented? Sure.



        I think the easiest way to do this, is this:




        • Store the index of the first selected item

        • Take out the items that you want to sort from the DataGridView

        • Sort the list using LINQ

        • Append the two lists and add the sorted list at the index stored in the first step.


        However you need to think about how you want to handle if you selecte items that are not followed by each other, for instance if you select index { 1, 3, 6, 9 } you might stil lwant to append this to index 1.



        Edit



        Okay so I played around with this a little bit and came up with a way that you can implement this. It's not very optimized but you'll get the idea on how I meant.



        First of all this is my SortSelectedIndices-method that I use:



        static IEnumerable<T> SortSelectedIndices<T>(
        IEnumerable<T> values,
        IEnumerable<int> selectedIndices,
        Func<IEnumerable<T>, IEnumerable<T>> sort)
        {
        var selectedValues = new List<T>();

        for (var i = 0; i < selectedIndices.Count(); i++)
        selectedValues.Add(values.ElementAt(selectedIndices.ElementAt(i)));

        var sortedList = sort(selectedValues);

        var finalList = new List<T>();

        var startPositionFound = false;
        for(var i = 0; i < values.Count(); i++)
        {
        if (selectedIndices.Contains(i))
        {
        if (startPositionFound) continue;

        startPositionFound = true;
        finalList.AddRange(sortedList);
        }
        else
        finalList.Add(values.ElementAt(i));
        }

        return finalList;
        }


        Then I call it like this:



        static void Main(string args)
        {
        var unsorted = new {3, 5, 6, 1, 2, 87, 432, 23, 46, 98, 44};
        var selected = new {1, 4, 7};

        Print(unsorted);

        var sort = new Func<IEnumerable<int>, IEnumerable<int>>(
        (x) => x.OrderBy(y => y).ToList());

        var sorted = SortSelectedIndices(unsorted, selected, sort);

        Print(sorted);
        }


        And this prints out the following:



        { 3,5,6,1,2,87,432,23,46,98,44 }
        { 3,2,5,23,6,1,87,432,46,98,44 }


        I am just using a simple method here to print this out to the console:



        static void Print<T>(IEnumerable<T> values)
        {
        Console.Write("{ ");
        Console.Write(string.Join(",", values));
        Console.WriteLine(" }");
        }


        So what you can do is to have a "sort"-button, when it's pressed you invoke SortSelectedIndices and then rebind the list when you're done. Remember I have not profiled or refactored this code, it might not be as fast as you like, I just want to give you an idea on what you can do to acheive the solution.






        share|improve this answer
















        Can this be done using the sort
        property of DGV




        No



        The Sort method on the DataGridView is used for a bit more simple sorting. Such as Ascending or Descending sorting and the SortOrder property is also just for "simple" sorting.



        Can this behavior be implemented? Sure.



        I think the easiest way to do this, is this:




        • Store the index of the first selected item

        • Take out the items that you want to sort from the DataGridView

        • Sort the list using LINQ

        • Append the two lists and add the sorted list at the index stored in the first step.


        However you need to think about how you want to handle if you selecte items that are not followed by each other, for instance if you select index { 1, 3, 6, 9 } you might stil lwant to append this to index 1.



        Edit



        Okay so I played around with this a little bit and came up with a way that you can implement this. It's not very optimized but you'll get the idea on how I meant.



        First of all this is my SortSelectedIndices-method that I use:



        static IEnumerable<T> SortSelectedIndices<T>(
        IEnumerable<T> values,
        IEnumerable<int> selectedIndices,
        Func<IEnumerable<T>, IEnumerable<T>> sort)
        {
        var selectedValues = new List<T>();

        for (var i = 0; i < selectedIndices.Count(); i++)
        selectedValues.Add(values.ElementAt(selectedIndices.ElementAt(i)));

        var sortedList = sort(selectedValues);

        var finalList = new List<T>();

        var startPositionFound = false;
        for(var i = 0; i < values.Count(); i++)
        {
        if (selectedIndices.Contains(i))
        {
        if (startPositionFound) continue;

        startPositionFound = true;
        finalList.AddRange(sortedList);
        }
        else
        finalList.Add(values.ElementAt(i));
        }

        return finalList;
        }


        Then I call it like this:



        static void Main(string args)
        {
        var unsorted = new {3, 5, 6, 1, 2, 87, 432, 23, 46, 98, 44};
        var selected = new {1, 4, 7};

        Print(unsorted);

        var sort = new Func<IEnumerable<int>, IEnumerable<int>>(
        (x) => x.OrderBy(y => y).ToList());

        var sorted = SortSelectedIndices(unsorted, selected, sort);

        Print(sorted);
        }


        And this prints out the following:



        { 3,5,6,1,2,87,432,23,46,98,44 }
        { 3,2,5,23,6,1,87,432,46,98,44 }


        I am just using a simple method here to print this out to the console:



        static void Print<T>(IEnumerable<T> values)
        {
        Console.Write("{ ");
        Console.Write(string.Join(",", values));
        Console.WriteLine(" }");
        }


        So what you can do is to have a "sort"-button, when it's pressed you invoke SortSelectedIndices and then rebind the list when you're done. Remember I have not profiled or refactored this code, it might not be as fast as you like, I just want to give you an idea on what you can do to acheive the solution.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jul 8 '11 at 9:04

























        answered Jul 7 '11 at 20:47









        Filip EkbergFilip Ekberg

        29.9k18107175




        29.9k18107175













        • How can this behavior be implemented?

          – techmanc
          Jul 7 '11 at 20:56











        • @techmanc, Did you try the steps that I wrote?

          – Filip Ekberg
          Jul 7 '11 at 20:58











        • @techmanc, I updated my answer with an example.

          – Filip Ekberg
          Jul 8 '11 at 8:33



















        • How can this behavior be implemented?

          – techmanc
          Jul 7 '11 at 20:56











        • @techmanc, Did you try the steps that I wrote?

          – Filip Ekberg
          Jul 7 '11 at 20:58











        • @techmanc, I updated my answer with an example.

          – Filip Ekberg
          Jul 8 '11 at 8:33

















        How can this behavior be implemented?

        – techmanc
        Jul 7 '11 at 20:56





        How can this behavior be implemented?

        – techmanc
        Jul 7 '11 at 20:56













        @techmanc, Did you try the steps that I wrote?

        – Filip Ekberg
        Jul 7 '11 at 20:58





        @techmanc, Did you try the steps that I wrote?

        – Filip Ekberg
        Jul 7 '11 at 20:58













        @techmanc, I updated my answer with an example.

        – Filip Ekberg
        Jul 8 '11 at 8:33





        @techmanc, I updated my answer with an example.

        – Filip Ekberg
        Jul 8 '11 at 8:33













        1














        Based on Filips definition of the problem, and his example as the correct answer, my somewhat less general (no generics, no Func) solution would be this:



        Public Function SortSelectedIndices(unsortedList As IEnumerable(Of Integer), selectedIndices As IEnumerable(Of Integer)) As IEnumerable(Of Integer)

        If Not selectedIndices.Any() Then
        Return unsortedList
        End If

        Dim extractedValues = From s In selectedIndices Select unsortedList(s)
        Dim sortedExtractedValues = From e In extractedValues Order By e

        Dim listWithoutExtractedValues = unsortedList.Except(extractedValues)
        Dim resultList = New List(Of Integer)(listWithoutExtractedValues)

        Dim firstSelectedIndex = Aggregate s In selectedIndices Order By s Into First()
        resultList.InsertRange(firstSelectedIndex, sortedExtractedValues)

        Return resultList

        End Function


        Edit: Filip just pointed out that the question is tagged "C#". But there is no mention of this in the text, so I deem it's not that important. I also assume that any reader familiar with .NET can translate "dim" to "var" and the likes, all by himself. :-P






        share|improve this answer






























          1














          Based on Filips definition of the problem, and his example as the correct answer, my somewhat less general (no generics, no Func) solution would be this:



          Public Function SortSelectedIndices(unsortedList As IEnumerable(Of Integer), selectedIndices As IEnumerable(Of Integer)) As IEnumerable(Of Integer)

          If Not selectedIndices.Any() Then
          Return unsortedList
          End If

          Dim extractedValues = From s In selectedIndices Select unsortedList(s)
          Dim sortedExtractedValues = From e In extractedValues Order By e

          Dim listWithoutExtractedValues = unsortedList.Except(extractedValues)
          Dim resultList = New List(Of Integer)(listWithoutExtractedValues)

          Dim firstSelectedIndex = Aggregate s In selectedIndices Order By s Into First()
          resultList.InsertRange(firstSelectedIndex, sortedExtractedValues)

          Return resultList

          End Function


          Edit: Filip just pointed out that the question is tagged "C#". But there is no mention of this in the text, so I deem it's not that important. I also assume that any reader familiar with .NET can translate "dim" to "var" and the likes, all by himself. :-P






          share|improve this answer




























            1












            1








            1







            Based on Filips definition of the problem, and his example as the correct answer, my somewhat less general (no generics, no Func) solution would be this:



            Public Function SortSelectedIndices(unsortedList As IEnumerable(Of Integer), selectedIndices As IEnumerable(Of Integer)) As IEnumerable(Of Integer)

            If Not selectedIndices.Any() Then
            Return unsortedList
            End If

            Dim extractedValues = From s In selectedIndices Select unsortedList(s)
            Dim sortedExtractedValues = From e In extractedValues Order By e

            Dim listWithoutExtractedValues = unsortedList.Except(extractedValues)
            Dim resultList = New List(Of Integer)(listWithoutExtractedValues)

            Dim firstSelectedIndex = Aggregate s In selectedIndices Order By s Into First()
            resultList.InsertRange(firstSelectedIndex, sortedExtractedValues)

            Return resultList

            End Function


            Edit: Filip just pointed out that the question is tagged "C#". But there is no mention of this in the text, so I deem it's not that important. I also assume that any reader familiar with .NET can translate "dim" to "var" and the likes, all by himself. :-P






            share|improve this answer















            Based on Filips definition of the problem, and his example as the correct answer, my somewhat less general (no generics, no Func) solution would be this:



            Public Function SortSelectedIndices(unsortedList As IEnumerable(Of Integer), selectedIndices As IEnumerable(Of Integer)) As IEnumerable(Of Integer)

            If Not selectedIndices.Any() Then
            Return unsortedList
            End If

            Dim extractedValues = From s In selectedIndices Select unsortedList(s)
            Dim sortedExtractedValues = From e In extractedValues Order By e

            Dim listWithoutExtractedValues = unsortedList.Except(extractedValues)
            Dim resultList = New List(Of Integer)(listWithoutExtractedValues)

            Dim firstSelectedIndex = Aggregate s In selectedIndices Order By s Into First()
            resultList.InsertRange(firstSelectedIndex, sortedExtractedValues)

            Return resultList

            End Function


            Edit: Filip just pointed out that the question is tagged "C#". But there is no mention of this in the text, so I deem it's not that important. I also assume that any reader familiar with .NET can translate "dim" to "var" and the likes, all by himself. :-P







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jul 8 '11 at 9:47

























            answered Jul 8 '11 at 9:39









            MEMarkMEMark

            1,0501327




            1,0501327























                0














                Definitely, the DataGridView cannot do this. So, the best solution would be to create a new collection (List), populate it with selected rows from the GridView and finally use its Sort method to order these rows. To sort data by a certain column, you can either write a custom IComparer class and pass it to the Sort method or use Linq:



                var orderedList = someList.OrderBy(obj => obj.TimeStampField);






                share|improve this answer




























                  0














                  Definitely, the DataGridView cannot do this. So, the best solution would be to create a new collection (List), populate it with selected rows from the GridView and finally use its Sort method to order these rows. To sort data by a certain column, you can either write a custom IComparer class and pass it to the Sort method or use Linq:



                  var orderedList = someList.OrderBy(obj => obj.TimeStampField);






                  share|improve this answer


























                    0












                    0








                    0







                    Definitely, the DataGridView cannot do this. So, the best solution would be to create a new collection (List), populate it with selected rows from the GridView and finally use its Sort method to order these rows. To sort data by a certain column, you can either write a custom IComparer class and pass it to the Sort method or use Linq:



                    var orderedList = someList.OrderBy(obj => obj.TimeStampField);






                    share|improve this answer













                    Definitely, the DataGridView cannot do this. So, the best solution would be to create a new collection (List), populate it with selected rows from the GridView and finally use its Sort method to order these rows. To sort data by a certain column, you can either write a custom IComparer class and pass it to the Sort method or use Linq:



                    var orderedList = someList.OrderBy(obj => obj.TimeStampField);







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jul 7 '11 at 20:49









                    platonplaton

                    4,86011421




                    4,86011421























                        0














                        You can do any conceivable sort, directly in the DataGridView, by creating a custom IComparer, and passing it to DataGridView.Sort(IComparer). The trick is to figure out how to give that IComparer the needed info.

                        See How to: Customize Sorting in the Windows Forms DataGridView Control / Custom Sorting Using the IComparer Interface , specifically class RowComparer : System.Collections.IComparer for details.



                        In your case, we must

                        a) associate each row with its original row number, and

                        b) indicate whether or not a row participates in the sort.



                        For the specific question, we want all the selected rows to stay after any rows before them, and before any rows after them. For example, if there are rows 0 - 9, and rows 3-7 are to be sorted, then rows 0-2 stay in their original order, as do rows 8 - 9. We can simplify the logic with a trick: assign the same row number to all the rows to be sorted, specifically the row number of the first such row. (3). Then when two rows have the same initial row number, sort on your sorting criteria.



                        One way to add this "extra" information to each row, is to add a "hidden" column to each row.



                        A second way is to put the information in a dictionary, and pass that in to your custom IComparer class.

                        (Untested) code for this way:



                        void SomeMethod()
                        {
                        DataGridView dgv = ...;

                        // Iterate through the rows, building the dictionary.
                        Dictionary<DataGridViewRow, int> rowToRowNumber = ...;
                        int iFirstSelected = -1;
                        for (int iRow = 0; iRow < dgv.Rows.Count; iRow++)
                        {
                        DataGridViewRow row = dgv.Rows[iRow];

                        int iAdjusted = iRow;
                        if (row.Selected)
                        {
                        if (iFirstSelected < 0)
                        iFirstSelected = iRow;
                        iAdjusted = iFirstSelected;
                        }
                        rowToRowNumber[row] = iAdjusted;
                        }

                        // Sort.
                        dgv.Sort(new RowComparer(rowToRowNumber));
                        }


                        private class RowComparer : System.Collections.IComparer
                        {
                        // Values are the row numbers before the sort was done,
                        // with all rows to sort set to the same value (the row number of the first row to sort).
                        Dictionary<DataGridViewRow, int> _rowToRowNumber;

                        public RowComparer(Dictionary<DataGridViewRow, int> rowToRowNumber)
                        {
                        _rowToRowNumber = rowToRowNumber;
                        }

                        public int Compare(object x, object y)
                        {
                        DataGridViewRow row1 = (DataGridViewRow)x;
                        DataGridViewRow row2 = (DataGridViewRow)y;

                        // Keep rows in order.
                        int result = _rowToRowNumber(row1).CompareTo(_rowToRowNumber(row2));
                        if (result != 0)
                        return result;

                        // Same row number, these are the rows to sort.
                        return CustomCompare(row1, row2);
                        }

                        private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
                        {
                        // Replace with your custom logic.
                        // TODO: If cells contain strings, may have to parse them into the
                        // original data types, and compare those typed values rather than the cell values themselves.
                        return row1.Cells[1].Value.CompareTo(row2.Cells[1].Value);
                        }
                        }


                        NOTE: If the object from which a row was created is in row.Tag, then it may be preferable to retrieve those typed objects, and do the comparison on their properties:



                            private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
                        {
                        MyClass ob1 = (MyClass)(row1.Tag);
                        MyClass ob2 = (MyClass)(row2.Tag);
                        return ob1.MyProp.CompareTo(ob2.MyProp);
                        }





                        share|improve this answer




























                          0














                          You can do any conceivable sort, directly in the DataGridView, by creating a custom IComparer, and passing it to DataGridView.Sort(IComparer). The trick is to figure out how to give that IComparer the needed info.

                          See How to: Customize Sorting in the Windows Forms DataGridView Control / Custom Sorting Using the IComparer Interface , specifically class RowComparer : System.Collections.IComparer for details.



                          In your case, we must

                          a) associate each row with its original row number, and

                          b) indicate whether or not a row participates in the sort.



                          For the specific question, we want all the selected rows to stay after any rows before them, and before any rows after them. For example, if there are rows 0 - 9, and rows 3-7 are to be sorted, then rows 0-2 stay in their original order, as do rows 8 - 9. We can simplify the logic with a trick: assign the same row number to all the rows to be sorted, specifically the row number of the first such row. (3). Then when two rows have the same initial row number, sort on your sorting criteria.



                          One way to add this "extra" information to each row, is to add a "hidden" column to each row.



                          A second way is to put the information in a dictionary, and pass that in to your custom IComparer class.

                          (Untested) code for this way:



                          void SomeMethod()
                          {
                          DataGridView dgv = ...;

                          // Iterate through the rows, building the dictionary.
                          Dictionary<DataGridViewRow, int> rowToRowNumber = ...;
                          int iFirstSelected = -1;
                          for (int iRow = 0; iRow < dgv.Rows.Count; iRow++)
                          {
                          DataGridViewRow row = dgv.Rows[iRow];

                          int iAdjusted = iRow;
                          if (row.Selected)
                          {
                          if (iFirstSelected < 0)
                          iFirstSelected = iRow;
                          iAdjusted = iFirstSelected;
                          }
                          rowToRowNumber[row] = iAdjusted;
                          }

                          // Sort.
                          dgv.Sort(new RowComparer(rowToRowNumber));
                          }


                          private class RowComparer : System.Collections.IComparer
                          {
                          // Values are the row numbers before the sort was done,
                          // with all rows to sort set to the same value (the row number of the first row to sort).
                          Dictionary<DataGridViewRow, int> _rowToRowNumber;

                          public RowComparer(Dictionary<DataGridViewRow, int> rowToRowNumber)
                          {
                          _rowToRowNumber = rowToRowNumber;
                          }

                          public int Compare(object x, object y)
                          {
                          DataGridViewRow row1 = (DataGridViewRow)x;
                          DataGridViewRow row2 = (DataGridViewRow)y;

                          // Keep rows in order.
                          int result = _rowToRowNumber(row1).CompareTo(_rowToRowNumber(row2));
                          if (result != 0)
                          return result;

                          // Same row number, these are the rows to sort.
                          return CustomCompare(row1, row2);
                          }

                          private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
                          {
                          // Replace with your custom logic.
                          // TODO: If cells contain strings, may have to parse them into the
                          // original data types, and compare those typed values rather than the cell values themselves.
                          return row1.Cells[1].Value.CompareTo(row2.Cells[1].Value);
                          }
                          }


                          NOTE: If the object from which a row was created is in row.Tag, then it may be preferable to retrieve those typed objects, and do the comparison on their properties:



                              private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
                          {
                          MyClass ob1 = (MyClass)(row1.Tag);
                          MyClass ob2 = (MyClass)(row2.Tag);
                          return ob1.MyProp.CompareTo(ob2.MyProp);
                          }





                          share|improve this answer


























                            0












                            0








                            0







                            You can do any conceivable sort, directly in the DataGridView, by creating a custom IComparer, and passing it to DataGridView.Sort(IComparer). The trick is to figure out how to give that IComparer the needed info.

                            See How to: Customize Sorting in the Windows Forms DataGridView Control / Custom Sorting Using the IComparer Interface , specifically class RowComparer : System.Collections.IComparer for details.



                            In your case, we must

                            a) associate each row with its original row number, and

                            b) indicate whether or not a row participates in the sort.



                            For the specific question, we want all the selected rows to stay after any rows before them, and before any rows after them. For example, if there are rows 0 - 9, and rows 3-7 are to be sorted, then rows 0-2 stay in their original order, as do rows 8 - 9. We can simplify the logic with a trick: assign the same row number to all the rows to be sorted, specifically the row number of the first such row. (3). Then when two rows have the same initial row number, sort on your sorting criteria.



                            One way to add this "extra" information to each row, is to add a "hidden" column to each row.



                            A second way is to put the information in a dictionary, and pass that in to your custom IComparer class.

                            (Untested) code for this way:



                            void SomeMethod()
                            {
                            DataGridView dgv = ...;

                            // Iterate through the rows, building the dictionary.
                            Dictionary<DataGridViewRow, int> rowToRowNumber = ...;
                            int iFirstSelected = -1;
                            for (int iRow = 0; iRow < dgv.Rows.Count; iRow++)
                            {
                            DataGridViewRow row = dgv.Rows[iRow];

                            int iAdjusted = iRow;
                            if (row.Selected)
                            {
                            if (iFirstSelected < 0)
                            iFirstSelected = iRow;
                            iAdjusted = iFirstSelected;
                            }
                            rowToRowNumber[row] = iAdjusted;
                            }

                            // Sort.
                            dgv.Sort(new RowComparer(rowToRowNumber));
                            }


                            private class RowComparer : System.Collections.IComparer
                            {
                            // Values are the row numbers before the sort was done,
                            // with all rows to sort set to the same value (the row number of the first row to sort).
                            Dictionary<DataGridViewRow, int> _rowToRowNumber;

                            public RowComparer(Dictionary<DataGridViewRow, int> rowToRowNumber)
                            {
                            _rowToRowNumber = rowToRowNumber;
                            }

                            public int Compare(object x, object y)
                            {
                            DataGridViewRow row1 = (DataGridViewRow)x;
                            DataGridViewRow row2 = (DataGridViewRow)y;

                            // Keep rows in order.
                            int result = _rowToRowNumber(row1).CompareTo(_rowToRowNumber(row2));
                            if (result != 0)
                            return result;

                            // Same row number, these are the rows to sort.
                            return CustomCompare(row1, row2);
                            }

                            private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
                            {
                            // Replace with your custom logic.
                            // TODO: If cells contain strings, may have to parse them into the
                            // original data types, and compare those typed values rather than the cell values themselves.
                            return row1.Cells[1].Value.CompareTo(row2.Cells[1].Value);
                            }
                            }


                            NOTE: If the object from which a row was created is in row.Tag, then it may be preferable to retrieve those typed objects, and do the comparison on their properties:



                                private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
                            {
                            MyClass ob1 = (MyClass)(row1.Tag);
                            MyClass ob2 = (MyClass)(row2.Tag);
                            return ob1.MyProp.CompareTo(ob2.MyProp);
                            }





                            share|improve this answer













                            You can do any conceivable sort, directly in the DataGridView, by creating a custom IComparer, and passing it to DataGridView.Sort(IComparer). The trick is to figure out how to give that IComparer the needed info.

                            See How to: Customize Sorting in the Windows Forms DataGridView Control / Custom Sorting Using the IComparer Interface , specifically class RowComparer : System.Collections.IComparer for details.



                            In your case, we must

                            a) associate each row with its original row number, and

                            b) indicate whether or not a row participates in the sort.



                            For the specific question, we want all the selected rows to stay after any rows before them, and before any rows after them. For example, if there are rows 0 - 9, and rows 3-7 are to be sorted, then rows 0-2 stay in their original order, as do rows 8 - 9. We can simplify the logic with a trick: assign the same row number to all the rows to be sorted, specifically the row number of the first such row. (3). Then when two rows have the same initial row number, sort on your sorting criteria.



                            One way to add this "extra" information to each row, is to add a "hidden" column to each row.



                            A second way is to put the information in a dictionary, and pass that in to your custom IComparer class.

                            (Untested) code for this way:



                            void SomeMethod()
                            {
                            DataGridView dgv = ...;

                            // Iterate through the rows, building the dictionary.
                            Dictionary<DataGridViewRow, int> rowToRowNumber = ...;
                            int iFirstSelected = -1;
                            for (int iRow = 0; iRow < dgv.Rows.Count; iRow++)
                            {
                            DataGridViewRow row = dgv.Rows[iRow];

                            int iAdjusted = iRow;
                            if (row.Selected)
                            {
                            if (iFirstSelected < 0)
                            iFirstSelected = iRow;
                            iAdjusted = iFirstSelected;
                            }
                            rowToRowNumber[row] = iAdjusted;
                            }

                            // Sort.
                            dgv.Sort(new RowComparer(rowToRowNumber));
                            }


                            private class RowComparer : System.Collections.IComparer
                            {
                            // Values are the row numbers before the sort was done,
                            // with all rows to sort set to the same value (the row number of the first row to sort).
                            Dictionary<DataGridViewRow, int> _rowToRowNumber;

                            public RowComparer(Dictionary<DataGridViewRow, int> rowToRowNumber)
                            {
                            _rowToRowNumber = rowToRowNumber;
                            }

                            public int Compare(object x, object y)
                            {
                            DataGridViewRow row1 = (DataGridViewRow)x;
                            DataGridViewRow row2 = (DataGridViewRow)y;

                            // Keep rows in order.
                            int result = _rowToRowNumber(row1).CompareTo(_rowToRowNumber(row2));
                            if (result != 0)
                            return result;

                            // Same row number, these are the rows to sort.
                            return CustomCompare(row1, row2);
                            }

                            private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
                            {
                            // Replace with your custom logic.
                            // TODO: If cells contain strings, may have to parse them into the
                            // original data types, and compare those typed values rather than the cell values themselves.
                            return row1.Cells[1].Value.CompareTo(row2.Cells[1].Value);
                            }
                            }


                            NOTE: If the object from which a row was created is in row.Tag, then it may be preferable to retrieve those typed objects, and do the comparison on their properties:



                                private int CustomCompare(DataGridViewRow row1, DataGridViewRow row2)
                            {
                            MyClass ob1 = (MyClass)(row1.Tag);
                            MyClass ob2 = (MyClass)(row2.Tag);
                            return ob1.MyProp.CompareTo(ob2.MyProp);
                            }






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jan 1 at 21:37









                            ToolmakerSteveToolmakerSteve

                            3,664135102




                            3,664135102






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f6616633%2fsorting-selected-rows-in-datagridview%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Angular Downloading a file using contenturl with Basic Authentication

                                Olmecas

                                Can't read property showImagePicker of undefined in react native iOS