在DataGridView中对选定的行进行排序

时间:2011-07-07 20:19:03

标签: c# sorting datagridview

我在Winforms应用程序中有一个DataGridView。我想在其中选择一组行,并按列(Timestamp)...

对这些行进行排序

其余行应保持原来的状态。 可以使用DGV的sort属性

来完成

由于

5 个答案:

答案 0 :(得分:3)

  

可以使用排序完成此操作   DGV的财产

DataGridView上的Sort method用于更简单的排序。例如Ascending或Descending排序,SortOrder属性也只是用于“简单”排序。

可以实施此行为吗?肯定。

我认为最简单的方法就是:

  • 存储第一个选定项目的索引
  • DataGridView
  • 中取出要排序的项目
  • 使用LINQ
  • 对列表进行排序
  • 附加两个列表,并将排序列表添加到第一步中存储的索引中。

但是,如果选择彼此不跟随的项目,则需要考虑如何处理,例如,如果选择索引{ 1, 3, 6, 9 },您可能希望将其附加到索引{{1} }。

修改

好的,所以我玩了一下这个,并提出了一种方法,你可以实现这一点。它不是很优化,但你会明白我的意思。

首先,这是我使用的1 - 方法:

SortSelectedIndices

然后我称之为:

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;
}

这打印出以下内容:

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);
}

我只是在这里使用一种简单的方法将其打印到控制台:

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

所以你可以做的就是有一个“排序”按钮,当你按下它时调用static void Print<T>(IEnumerable<T> values) { Console.Write("{ "); Console.Write(string.Join(",", values)); Console.WriteLine(" }"); } 然后在你完成时重新绑定列表。 请记住我没有对此代码进行分析或重构,它可能没有您想要的那么快,我只想告诉您如何实现该解决方案。

答案 1 :(得分:1)

基于Filips对问题的定义,以及他作为正确答案的例子,我的一般性(没有泛型,没有Func)解决方案就是这样:

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

编辑:Filip刚刚指出问题标记为“C#”。但是在文中没有提到这一点,所以我认为它并不重要。我还假设任何熟悉.NET的读者都可以将“昏暗”翻译成“var”和喜欢的东西。 :-P

答案 2 :(得分:0)

当然,DataGridView无法做到这一点。因此,最好的解决方案是创建一个新的集合(List),用GridView中的选定行填充它,最后使用它的Sort方法来排序这些行。要按特定列对数据进行排序,您可以编写自定义IComparer类并将其传递给Sort方法或使用Linq:

var orderedList = someList.OrderBy(obj =&gt; obj.TimeStampField);

答案 3 :(得分:0)

您可以直接在DataGridView中进行任何可能的排序,方法是创建一个自定义IComparer,并将其传递给DataGridView.Sort(IComparer)。诀窍是弄清楚如何为IComparer提供所需的信息。
有关详细信息,请参见How to: Customize Sorting in the Windows Forms DataGridView Control / Custom Sorting Using the IComparer Interface,尤其是class RowComparer : System.Collections.IComparer

在您的情况下,我们必须
a)将每一行与其原始行号相关联,并且
b)指出是否有行参与排序。

对于特定问题,我们希望所有选定的行都保留在它们之前的任何行之后,以及它们之后的任何行之前。例如,如果要对0-9行进行排序,而对3-7行进行排序,则0-2行将保持其原始顺序,而8-9行也是如此。与要排序的所有行相同的行号,特别是第一行的行号。 (3)。然后,当两行具有相同的初始行号时,请按照您的排序标准进行排序。

向每行添加此“额外”信息的一种方法是向每行添加“隐藏”列。

第二种方法是将信息放入字典中,并将其传递给自定义IComparer类。
(未经测试的)代码采用这种方式:

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);
    }
}

注意:如果创建行的对象位于row.Tag中,则最好检索这些类型的对象,并对其属性进行比较:

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

答案 4 :(得分:0)

没有太多时间来解释,但这是我曾经做过的事情。

afterEach