web-dev-qa-db-ja.com

ユーザーが列ヘッダーをクリックしたときに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をデフォルトのソートとして使用しますが、ユーザーが列ヘッダーをクリックしたときにソートできるようにしたいと思います。

この並べ替えはnotデータを変更します。目で画面をスキャンするときに情報を簡単に検索できるようにするのはクライアント側のボーナスです。

提案をありがとう。

66
delete

すべての列(ユーザーがソート可能)の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;
    }

Edit:datagridviewはlinqクエリにバインドされているため、ソートされません。したがって、この link を実行して、ソート可能なバインディングリストを作成し、それをデータソースとしてdatagridviewにフィードする方法を説明してください。

49
Marshal

Nirajが提案したように、SortableBindingListを使用します。 DataGridViewでこれを非常にうまく使用しました。

ここに私が使用した更新されたコードへのリンクがあります- SortableBindingListの提示-Take Two

2つのソースファイルをプロジェクトに追加するだけで、作業が開始されます。

ソースは 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;
    }

そして、次のように各ダトラグリッドのイベントを初期化します。

        dataGridView1.DataBindingComplete += MakeColumnsSortable_DataBindingComplete;
7
Saneesh B

バインディングデータソースを作成する必要はありません。すべての列に並べ替えを適用する場合は、より一般的なソリューションを次に示します。

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
0014

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

これを行うもう1つの方法は、「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>メソッドはsortableバインディングリストの実装を返します。この仮定を確認するソースコードは見つかりませんでしたが、特にヘッダーをクリックして列を並べ替える場合、このメソッドから返されるオブジェクトは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;
3
Adam Matecki

KISS:シンプルで愚かなこと

方法A:独自の SortableBindingList を使用する場合はクラスを実装しますDataBindingおよびsorting

Way B:List <string>ソートを使用することもできますが、DataBinding

2
hfrmobile

次のようなエラーメッセージが表示された場合

System.Windows.Forms.dllでタイプ 'System.NullReferenceException'の未処理の例外が発生しました

sortableBindingListを使用する場合、コードはおそらくDataGridViewの行でいくつかのループを使用し、空の最後の行にアクセスしようとします! (BindingSource = null)

ユーザーがDataGridViewに新しい行を直接追加できるようにする必要がない場合、このコード行は簡単に問題を解決します。

InitializeComponent();
m_dataGridView.AllowUserToAddRows = false; // after components initialized
...
1
leon22
  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. Datagrid addを含むフォーム内

    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

データソースとしてdataGridViewにバインドするBindingList <>オブジェクトがあります。

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

列ヘッダーをクリックしても、ソートは行われません。 Tom Bushellが提供するSortableBindingList回答を使用しました。 2つのソースファイルをプロジェクトに含めたこと

  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;

これらの変更の後、プログラムでビルドを実行しました。列ヘッダーをクリックしてソートできるようになりました。変更する必要があるのは2行のみです。上記のコードスニペットでは、コメントの末尾で強調表示されています。

0
user3674642

DataTable.DefaultViewをDataSourceとして使用することをお勧めします。次に、以下の行。

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

その後、gridview自体がソートを管理します(昇順または降順がサポートされます)。

0
Milad

私の場合、問題はDataSourceobjectに設定していたため、ソートされなかったためです。 objectからDataTableに変更した後、コードを補完することなく正常に機能しました。

0

誰かがまだそれを探している場合に備えて、VS 2008 C#で実行しました。

Event ColumnHeaderMouseClickで、gridviewのデータバインディングを追加し、パラメーターのようなフィールドごとの順序を送信します。クリックしたフィールドは次のように取得できます。

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