it-swarm.com.ru

Как включить сортировку DataGridView, когда пользователь нажимает на заголовок столбца?

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

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 в качестве сортировки по умолчанию, но я также хотел бы позволить пользователям сортировать при нажатии на заголовок столбца.

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

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

66
delete

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

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

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

46
Marshal

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

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

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

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

26
Tom Bushell

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

Создайте этот обработчик событий:

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

И инициализируйте событие каждого из ваших datragrid как это:

        dataGridView1.DataBindingComplete += MakeColumnsSortable_DataBindingComplete;
7
Saneesh B

Вы можете использовать событие 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()
    }
}
5
thinzar

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

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. Когда пользователь нажимает на столбец, он сортируется по убыванию. Если снова щелкнуть тот же заголовок столбца, сортировка будет выполняться по возрастанию.

4
0014


Существует довольно простое решение при использовании 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;
3
Adam Matecki

Еще один способ сделать это - использовать библиотеку 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
Vidhyardhi Gorrepati

ПОЦЕЛУЙ: будь проще, глупый

Путь A: Реализуйте собственный класс SortableBindingList , когда хотите использовать DataBinding и sorting.

Путь B: Использование сортировки List <string> также работает, но не работает с DataBinding.

2
hfrmobile

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

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

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

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

InitializeComponent();
m_dataGridView.AllowUserToAddRows = false; // after components initialized
...
1
leon22

Я предлагаю использовать DataTable.DefaultView в качестве источника данных. Тогда строка ниже.

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

После этого само представление сетки будет управлять сортировкой (поддерживается Ascending или Descending.)

1
Milad
  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 <Student>, чтобы иметь возможность сортировать

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

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

1
Albert

У меня есть привязка объекта BindingList <> в качестве источника данных для dataGridView.

BindingList x1;
x1 = new BindingList<sourceObject>();
BindingSource bsx1 = new BindingSource();
bsx1.DataSource = x1;
dataGridView1.DataSource = bsx1;

Когда я щелкнул заголовок столбца, сортировка не выполнялась. Я использовал ответ SortableBindingList, предоставленный Томом Бушеллом. Включив два исходных файла в мой проект

  1. SortableBindingList.cs
  2. PropertyComparer.cs

Затем это изменение вносится в мой код:

Be.Timvw.Framework.ComponentModel.SortableBindingList x1;                       // 1
x1 = new Be.Timvw.Framework.ComponentModel.SortableBindingList<sourceObject>(); // 2
BindingSource bsx1 = new BindingSource();
bsx1.DataSource = x1;
dataGridView1.DataSource = bsx1;

После этих изменений я выполнил сборку своей программы. Теперь я могу сортировать, нажимая заголовки столбцов. Нужно изменить только две строки, они выделены в фрагменте кода выше завершающими комментариями. 

0
user3674642

В моем случае проблема заключалась в том, что я установил свой DataSource как object, поэтому он не был отсортирован. После изменения с object на DataTable он работал хорошо без какого-либо дополнения кода. 

0
Elvis Silva Noleto

На всякий случай, если кто-то все еще ищет это, я сделал это на VS 2008 C #.

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

dgView.Columns[e.ColumnIndex].Name

В моем случае имена заголовков похожи на имена полей просмотра.

0
Hugo Bazan

поместите эту строку в форму Windows (при загрузке или лучше в публичном методе, таком как "binddata"): 

//
// bind the data and make the grid sortable 
//
this.datagridview1.MakeSortable( myenumerablecollection ); 

Поместите этот код в файл с именем DataGridViewExtensions.cs (или аналогичный) 

// MakeSortable extension. 
// this will make any enumerable collection sortable on a datagrid view.  

//
// BEGIN MAKESORTABLE - Mark A. Lloyd
//
// Enables sort on all cols of a DatagridView 

//



    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    public static class DataGridViewExtensions
    {
    public static void MakeSortable<T>(
        this DataGridView dataGridView, 
        IEnumerable<T> dataSource,
        SortOrder defaultSort = SortOrder.Ascending, 
        SortOrder initialSort = SortOrder.None)
    {
        var sortProviderDictionary = new Dictionary<int, Func<SortOrder, IEnumerable<T>>>();
        var previousSortOrderDictionary = new Dictionary<int, SortOrder>();
        var itemType = typeof(T);
        dataGridView.DataSource = dataSource;
        foreach (DataGridViewColumn c in dataGridView.Columns)
        {
            object Provider(T info) => itemType.GetProperty(c.Name)?.GetValue(info);
            sortProviderDictionary[c.Index] = so => so != defaultSort ? 
                dataSource.OrderByDescending<T, object>(Provider) : 
                dataSource.OrderBy<T,object>(Provider);
            previousSortOrderDictionary[c.Index] = initialSort;
        }

        async Task DoSort(int index)
        {

            switch (previousSortOrderDictionary[index])
            {
                case SortOrder.Ascending:
                    previousSortOrderDictionary[index] = SortOrder.Descending;
                    break;
                case SortOrder.None:
                case SortOrder.Descending:
                    previousSortOrderDictionary[index] = SortOrder.Ascending;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            IEnumerable<T> sorted = null;
            dataGridView.Cursor = Cursors.WaitCursor;
            dataGridView.Enabled = false;
            await Task.Run(() => sorted = sortProviderDictionary[index](previousSortOrderDictionary[index]).ToList());
            dataGridView.DataSource = sorted;
            dataGridView.Enabled = true;
            dataGridView.Cursor = Cursors.Default;

        }

        dataGridView.ColumnHeaderMouseClick+= (object sender, DataGridViewCellMouseEventArgs e) => DoSort(index: e.ColumnIndex);
    }
}
0
Mark Lloyd