Сортировка выбранных строк в DataGridView - PullRequest
5 голосов
/ 08 июля 2011

У меня есть DataGridView в приложении Winforms.Я хочу выбрать набор строк в нем и отсортировать эти строки по столбцу (Timestamp) ...

Остальные строки должны остаться, как они были изначально. Это можно сделать с помощью свойства sortДГВ

Спасибо

Ответы [ 4 ]

3 голосов
/ 08 июля 2011

Можно ли это сделать с помощью сортировки собственность DGV

нет

Нет

Метод Sort на DataGridView используется для более простой сортировки. Такие как сортировка по возрастанию или по убыванию и свойство SortOrder также предназначены только для «простой» сортировки.

Можно ли реализовать это поведение? Конечно.

Я думаю, что самый простой способ сделать это, это:

  • Сохранить индекс первого выбранного элемента
  • Извлеките предметы, которые вы хотите отсортировать из DataGridView
  • Сортировка списка с помощью LINQ
  • Добавьте два списка и добавьте отсортированный список к индексу, сохраненному на первом шаге.

Однако вам нужно подумать о том, как вы хотите обрабатывать, если вы выбираете элементы, за которыми не следуют друг за другом, например, если вы выбираете индекс { 1, 3, 6, 9 }, вы можете добавить это к индексу 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(" }");
}

Итак, что вы можете сделать, так это иметь кнопку «сортировки», когда она нажата, вы вызываете SortSelectedIndices, а затем перепривязываете список, когда закончите. Помните Я не профилировал и не реорганизовал этот код, он может работать не так быстро, как вам хотелось бы, я просто хочу дать вам представление о том, что вы можете сделать, чтобы добиться решения.

1 голос
/ 08 июля 2011

Исходя из определения задачи Филипса и его примера в качестве правильного ответа, мое несколько менее общее (без обобщений, без 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

Редактировать: Филипп только что отметил, что вопрос помечен "C #". Но об этом нет упоминания в тексте, поэтому я считаю, что это не так важно. Я также предполагаю, что любой читатель, знакомый с .NET, может перевести «dim» в «var» и тому подобное, все самому. : -Р

0 голосов
/ 02 января 2019

Вы можете выполнить любую возможную сортировку непосредственно в DataGridView, создав собственный IComparer и передав его в DataGridView.Sort (IComparer).Хитрость заключается в том, чтобы выяснить, как дать этому IComparer необходимую информацию.
См. Как: настроить сортировку в элементе управления DataGridView Windows Forms / пользовательскую сортировку с помощью интерфейса IComparer , в частности 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);
    }        
0 голосов
/ 08 июля 2011

Определенно, DataGridView не может этого сделать.Таким образом, лучшим решением будет создание новой коллекции (List), заполнение ее выбранными строками из GridView и, наконец, использование метода Sort для упорядочивания этих строк.Чтобы отсортировать данные по определенному столбцу, вы можете либо написать собственный класс IComparer и передать его в метод Sort, либо использовать Linq:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...