사용자가 열 머리글을 클릭 할 때 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
...
필요한 모든 속성을 포함하는 클래스를 만들고 생성자에 채 웁니다.
class Student { int _StudentId; public int StudentId {get;} string _Name; public string Name {get;} ... public Student(int studentId, string name ...) { _StudentId = studentId; _Name = name; ... } }
정렬 할 수 있도록 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; } }
데이터 그리드가 포함 된 양식 내에서 추가
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]; }
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
- SortableBindingList.cs
- 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.
'program tip' 카테고리의 다른 글
java.lang.NoSuchMethodError 메시지 해석 (0) | 2020.11.15 |
---|---|
이름으로 Python 메서드 호출 (0) | 2020.11.15 |
파이썬에서는 왜 인쇄 대신 로깅을 사용합니까? (0) | 2020.11.15 |
KnockoutJS에서 $ data 변수의 기원과 목적은 무엇입니까? (0) | 2020.11.15 |
C ++ 11 "자동"의미 (0) | 2020.11.15 |