Как включить сортировку DataGridView, когда пользователь нажимает на заголовок столбца? - PullRequest
66 голосов
/ 05 апреля 2011

В моей форме есть сетевое представление, и я заполняю его:

dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })
                                   .OrderBy(s => s.Apellidos)
                                   .ToList();

Теперь я использую s.Apellidos в качестве сортировки по умолчанию, но я также хотел бы разрешить пользователям сортировать при нажатии на заголовок столбца.

Этот тип не изменяет данные каким-либо образом, это всего лишь бонус со стороны клиента, чтобы упростить поиск информации при сканировании экрана их глазами.

Спасибо за предложения.

Ответы [ 15 ]

49 голосов
/ 05 апреля 2011

Установить для свойства столбца (которое может быть отсортировано пользователями) свойство SortMode значение Автоматически

dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })
                                   .OrderBy(s => s.Apellidos)
                                   .ToList();

    foreach(DataGridViewColumn column in dataGridView1.Columns)
    {

        column.SortMode = DataGridViewColumnSortMode.Automatic;
    }

Редактировать: Поскольку ваше представление данных связано с запросом linq, оно не будет отсортировано. Поэтому, пожалуйста, пройдите по этой ссылке , которая объясняет, как создать сортируемый список привязок и затем передать его как источник данных в datagridview.

26 голосов
/ 05 апреля 2011

Как предложил Нирадж, используйте SortableBindingList . Я очень успешно использовал это с DataGridView.

Вот ссылка на обновленный код, который я использовал - Представление списка SortableBindingList - Take Two

Просто добавьте два исходных файла в свой проект, и вы будете в бизнесе.

Источник находится в SortableBindingList.zip

7 голосов
/ 25 августа 2011

ваша сетка данных должна быть связана с сортируемым списком в первую очередь.

Создать этот обработчик события:

    void MakeColumnsSortable_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
    {
        //Add this as an event on DataBindingComplete
        DataGridView dataGridView = sender as DataGridView;
        if (dataGridView == null)
        {
            var ex = new InvalidOperationException("This event is for a DataGridView type senders only.");
            ex.Data.Add("Sender type", sender.GetType().Name);
            throw ex;
        }

        foreach (DataGridViewColumn column in dataGridView.Columns)
            column.SortMode = DataGridViewColumnSortMode.Automatic;
    }

И инициализируйте событие каждой из ваших сетей данных следующим образом:

        dataGridView1.DataBindingComplete += MakeColumnsSortable_DataBindingComplete;
5 голосов
/ 26 августа 2017

Вам не нужно создавать обязательный источник данных. Если вы хотите применить сортировку для всех ваших столбцов, вот мое более общее решение:

private int _previousIndex;
private bool _sortDirection;

private void gridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex == _previousIndex)
        _sortDirection ^= true; // toggle direction

    gridView.DataSource = SortData(
        (List<MainGridViewModel>)gridReview.DataSource, gridReview.Columns[e.ColumnIndex].Name, _sortDirection);

    _previousIndex = e.ColumnIndex;
}

public List<MainGridViewModel> SortData(List<MainGridViewModel> list, string column, bool ascending)
{
    return ascending ? 
        list.OrderBy(_ => _.GetType().GetProperty(column).GetValue(_)).ToList() :
        list.OrderByDescending(_ => _.GetType().GetProperty(column).GetValue(_)).ToList();
}

Убедитесь, что вы подписали свою сетку данных на событие ColumnHeaderMouseClick. Когда пользователь нажимает на столбец, он сортируется по убыванию. Если снова щелкнуть тот же заголовок столбца, сортировка будет выполняться по возрастанию.

5 голосов
/ 21 июля 2011

Вы можете использовать событие DataGridViewColoumnHeaderMouseClick следующим образом:

Private string order = String.Empty;
private void dgvDepartment_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
    if (order == "d")
{
        order = "a";                
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })   .OrderBy(s => s.Apellidos).ToList();
    }
    else
    {
        order = "d";
        dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth }.OrderByDescending(s => s.Apellidos)  .ToList()
    }
}
4 голосов
/ 19 апреля 2017

Еще один способ сделать это - использовать библиотеку "System.Linq.Dynamic".Вы можете получить эту библиотеку из Nuget .Нет необходимости в каких-либо пользовательских реализациях или сортируемых списках:)

using System.Linq.Dynamic;
private bool sortAscending = false;

private void dataGridView_ColumnHeaderMouseClick ( object sender, DataGridViewCellMouseEventArgs e )
{
    if ( sortAscending )
        dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).ToList ( );
    else
        dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).Reverse ( ).ToList ( );
    sortAscending = !sortAscending;
}
3 голосов
/ 03 ноября 2016


Существует довольно простое решение при использовании Entity Framework (в данном случае версия 6). Я не уверен, но, похоже, ObservableCollectionExtensions.ToBindingList<T> метод возвращает реализацию списка связывания sortable . Я не нашел исходный код, чтобы подтвердить это предположение, но объект, возвращаемый этим методом, очень хорошо работает с DataGridView, особенно при сортировке столбцов, щелкая по заголовкам.

Код очень прост и основан только на классах .net и Entity Framework:

using System.Data.Entity;

IEnumerable<Item> items = MethodCreatingItems();

var observableItems = new System.Collections.ObjectModel.ObservableCollection<Item>(items);
System.ComponentModel.BindingList<Item> source = observableItems.ToBindingList();

MyDataGridView.DataSource = source;
2 голосов
/ 15 июля 2012

KISS: Сохраняйте это простым, глупым

Способ A: Реализация собственного класса SortableBindingList , когда вы хотите использовать DataBinding и сортировка .

Способ B: Использовать Список сортировка также работает, но не работает с DataBinding .

1 голос
/ 17 июня 2013

Если вы получаете сообщение об ошибке типа

Необработанное исключение типа 'System.NullReferenceException' произошло в System.Windows.Forms.dll

если вы работаете с SortableBindingList, ваш код, вероятно, использует некоторые циклы над строками DataGridView, а также пытается получить доступ к пустой последней строке! (BindingSource = null)

Если вам не нужно разрешать пользователю добавлять новые строки непосредственно в DataGridView, эта строка кода легко решит проблему:

InitializeComponent();
m_dataGridView.AllowUserToAddRows = false; // after components initialized
...
1 голос
/ 05 апреля 2011
  1. Создайте класс, который содержит все нужные вам свойства, и заполните их в конструкторе

    class Student
    {
        int _StudentId;
        public int StudentId {get;}
        string _Name;
        public string Name {get;}
        ...
    
        public Student(int studentId, string name ...)
        { _StudentId = studentId; _Name = name; ... }
    }
    
  2. Создайте класс IComparer , который будетвозможность сортировки

    class StudentSorter : IComparer<Student>
    {
        public enum SField {StudentId, Name ... }
        SField _sField; SortOrder _sortOrder;
    
        public StudentSorder(SField field, SortOrder order)
        { _sField = field; _sortOrder = order;}
    
        public int Compare(Student x, Student y)
        {
            if (_SortOrder == SortOrder.Descending)
            {
                Student tmp = x;
                x = y;
                y = tmp;
            }
    
            if (x == null || y == null)
                return 0;
    
            int result = 0;
            switch (_sField)
            {
                case SField.StudentId:
                    result = x.StudentId.CompareTo(y.StudentId);
                    break;
                case SField.Name:
                    result = x.Name.CompareTo(y.Name);
                    break;
                    ...
            }
    
            return result;
        }
    }
    
  3. В форме, содержащей сетку данных, добавить

    ListDictionary sortOrderLD = new ListDictionary(); //if less than 10 columns
    private SortOrder SetOrderDirection(string column)
    {
        if (sortOrderLD.Contains(column))
        {
            sortOrderLD[column] = (SortOrder)sortOrderLD[column] == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
        }
        else
        {
            sortOrderLD.Add(column, SortOrder.Ascending);
        }
    
        return (SortOrder)sortOrderLD[column];
    }
    
  4. В обработчике событий datagridview_ColumnHeaderMouseClick сделать что-то подобное

    private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
    {
        StudentSorter sorter = null;
        string column = dGV.Columns[e.ColumnIndex].DataPropertyName; //Use column name if you set it
        if (column == "StudentId")
        {
            sorter = new StudentSorter(StudentSorter.SField.StudentId, SetOrderDirection(column));
        }
        else if (column == "Name")
        {
            sorter = new StudentSorter(StudentSorter.SField.Name, SetOrderDirection(column));
        }
    
        ...
    
        List<Student> lstFD = datagridview.DataSource as List<Student>;
        lstFD.Sort(sorter);
        datagridview.DataSource = lstFD;
        datagridview.Refresh();
    }
    

Надеюсь, это поможет

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