program tip

사용자가 열 머리글을 클릭 할 때 DataGridView 정렬을 활성화하는 방법은 무엇입니까?

radiobox 2020. 11. 15. 11:07
반응형

사용자가 열 머리글을 클릭 할 때 DataGridView 정렬을 활성화하는 방법은 무엇입니까?


내 양식에 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를 기본 정렬로 사용하지만 사용자가 열 머리글을 클릭 할 때 정렬 할 수 있도록하고 싶습니다.

이 종류는 어떤 식 으로든 데이터를 수정 하지 않으며 , 눈으로 화면을 스캔 할 때 정보를 더 쉽게 검색 할 수 있도록하는 클라이언트 측 보너스 일뿐입니다.

제안 해 주셔서 감사합니다.


모든 열 (사용자가 정렬 할 수 있음) 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;
    }

편집 : datagridview가 linq 쿼리에 바인딩되어 있으므로 정렬되지 않습니다. 따라서 정렬 가능한 바인딩 목록을 만들고 datagridview에 데이터 소스로 공급하는 방법을 설명하는 링크통해 이동하십시오 .


Niraj가 제안했듯이 SortableBindingList를 사용하십시오 . DataGridView와 함께 이것을 매우 성공적으로 사용했습니다.

여기 내가 사용한 업데이트 된 코드에 대한 링크가 있습니다.- SortableBindingList 제시-Take Two

두 개의 소스 파일을 프로젝트에 추가하기 만하면됩니다.

소스는 SortableBindingList.zip에 있습니다.


데이터 그리드는 우선 정렬 가능한 목록에 바인딩되어야합니다.

이 이벤트 핸들러를 만듭니다.

    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;

다음과 같이 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()
    }
}

바인딩 데이터 소스를 만들 필요가 없습니다. 모든 열에 대해 정렬을 적용하려면 여기에 좀 더 일반적인 솔루션이 있습니다.

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. 사용자가 열을 클릭하면 내림차순으로 정렬됩니다. 같은 열 헤더를 다시 클릭하면 오름차순으로 정렬됩니다.


이를위한 또 다른 방법은 "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;
}


Entity Framework (이 경우 버전 6)를 사용할 때 아주 간단한 해결책이 있습니다. 확실하지 않지만 ObservableCollectionExtensions.ToBindingList<T>메서드가 정렬 가능한 바인딩 목록의 구현을 반환 하는 것 같습니다 . 이 가정을 확인하는 소스 코드를 찾지 못했지만이 메서드에서 반환하는 개체는 DataGridView특히 헤더를 클릭하여 열을 정렬 할 때 매우 잘 작동합니다 .

코드는 매우 간단하며 .net 및 엔티티 프레임 워크 클래스에만 의존합니다.

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;

키스 : 단순하고 멍청하게

방법 A : DataBinding정렬 을 사용하려는 경우 자체 SortableBindingList 클래스를 구현합니다 .

방법 B : 사용하십시오 목록 <문자열> 정렬도 작동하지만 함께 작업을하지 않는 데이터 바인딩 .


다음과 같은 오류 메시지가 표시되는 경우

System.Windows.Forms.dll에서 'System.NullReferenceException'유형의 처리되지 않은 예외가 발생했습니다.

SortableBindingList로 작업하는 경우 코드에서 DataGridView 행에 대해 일부 루프를 사용하고 빈 마지막 행에 액세스하려고합니다! (BindingSource = null)

사용자가 DataGridView에 새 행을 직접 추가하도록 허용 할 필요가없는 경우이 코드 줄은 문제를 쉽게 해결합니다.

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

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

도움이 되었기를 바랍니다


누군가가 여전히 그것을 찾는 경우를 대비하여 VS 2008 C #에서 수행했습니다.

Event ColumnHeaderMouseClick에서 gridview에 대한 데이터 바인딩을 추가하고 매개 변수처럼 order by 필드를 보냅니다. 클릭 한 필드는 다음과 같이 얻을 수 있습니다.

dgView.Columns[e.ColumnIndex].Name

제 경우에는 헤더의 이름이 뷰 필드 이름과 비슷합니다.


BindingList <> 개체가 dataGridView에 데이터 소스로 바인딩되어 있습니다.

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

When I clicked the column header, no sorting takes place. I used the SortableBindingList answer provided by Tom Bushell. Having included two source files into my project

  1. SortableBindingList.cs
  2. PropertyComparer.cs

Then this change is made to my code:

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;

After these changes I performed a build on my program. I am now able to sort by clicking the column headers. Only two lines need changing, they are highlighted in the code snippet above by trailing comments.


I suggest using a DataTable.DefaultView as a DataSource. Then the line below.

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

After that the gridview itself will manage sorting(Ascending or Descending is supported.)


put this line in your windows form (on load or better in a public method like "binddata" ):

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

Put this code in a file called DataGridViewExtensions.cs (or similar)

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

In my case, the problem was that I had set my DataSource as an object, which is why it didn't get sorted. After changing from object to a DataTable it workd well without any code complement.

참고URL : https://stackoverflow.com/questions/5553100/how-to-enable-datagridview-sorting-when-user-clicks-on-the-column-header

반응형