Martin
Martin

Reputation: 40365

How to sort DataGridView when bound to a binding source that is linked to an EF4 Entity

I have a DataGridView that is linked to a BindingSource.

My BindingSource is linked to an IQueryable list of entities:

    public void BindTo(IQueryable elements)
    {
        BindingSource source = new BindingSource();
        source.DataSource = elements;

        bindingNavigator1.BindingSource = source;
        dataGridView1.DataSource = source;

    }

I am wanting my users to be able to click on the grid headers to sort the data - struggling to get this to work. Is it possible? If so, how do I do it?

Upvotes: 21

Views: 29080

Answers (6)

Vitalij Roscinski
Vitalij Roscinski

Reputation: 134

I suggest you to dynamically convert entities into data table. There is a method

 public static DataTable GetTableFromList<T>(IEnumerable<T> list)
    {
        DataTable dt = new DataTable();
        PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

        foreach (PropertyInfo property in properties)
            dt.Columns.Add(property.Name, property.PropertyType);

        foreach (T item in list)
        {
            DataRow newRow = dt.NewRow();
            foreach (PropertyInfo property in properties)
            {
                newRow[property.Name] = property.GetValue(item);
            }
                dt.Rows.Add(newRow);
        }

        return dt;
    }

After conversion pass table into bindingsource

source.DataSource = GetTableFromList<T>(elements);

Be aware of property types that cannot be converted into a column types.

Upvotes: 1

Lucien ASSAILLIT
Lucien ASSAILLIT

Reputation: 1

maybe this will help you.

internal class CustomDataGridView : DataGridView
{   
    public SortOrder MySortOrder { get; set; }
    protected override void OnColumnHeaderMouseClick(DataGridViewCellMouseEventArgs e)
    {
        BindingSource MyBindingSource = (BindingSource)base.DataSource;
        DataTable MyDataTable = (DataTable)MyBindingSource.DataSource;
        switch (MySortOrder)
        {
            case SortOrder.None:
                MyDataTable.DefaultView.Sort = base.Columns[e.ColumnIndex].Name + " ASC";
                MyDataTable = MyDataTable.DefaultView.ToTable();
                MyBindingSource.DataSource = MyDataTable;
                MySortOrder = SortOrder.Ascending;
                break;

            case SortOrder.Ascending:
                MyDataTable.DefaultView.Sort = base.Columns[e.ColumnIndex].Name + " DESC";
                MyDataTable = MyDataTable.DefaultView.ToTable();
                MyBindingSource.DataSource = MyDataTable;
                MySortOrder = SortOrder.Descending;
                break;

            case SortOrder.Descending:
                MyDataTable.DefaultView.Sort = Properties.Settings.Default.OderDataGridView; //SqlOriginOrder
                MyDataTable = MyDataTable.DefaultView.ToTable();
                MyBindingSource.DataSource = MyDataTable;
                MySortOrder = SortOrder.None;
                break;
        }
        base.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = MySortOrder; //mini arrow 
    }
}

Upvotes: 0

islandTrader
islandTrader

Reputation: 11

This code snippet works very well, and fast enough for most purposes...

int iColNumber = 3; //e.g., sorting on the 3rd column of the DGV

MyBindingSource.DataSource = MyBindingList.OrderByDescending(o => o.GetType().GetProperty(MyDataGridView.Columns[iColNumber].Name).GetValue(o));

Upvotes: 1

Pat
Pat

Reputation: 16911

Yes, it is possible to easily have a sortable DGV when bound to EF data. Use the BindingListView from the BLW library (also, check out How do I implement automatic sorting of DataGridView?).

public void BindTo(IQueryable elements)
{
    BindingSource source = new BindingSource();
    source.DataSource = new BindingListView(elements.ToList());

    bindingNavigator1.BindingSource = source;
    dataGridView1.DataSource = source;

}

In my tests, even when .ToList() was called within the constructor (as above), changes were propagated to the DB, which surprised me.

Upvotes: 1

user2019717
user2019717

Reputation: 11

VB.NET

If you are using a bindingsource with linq syntax you can sort your data like this

In this case When loading a bindningsource associated with a datagridview from entity framwork objects "NCFile" with having a foreign column to a list of "NCFilePartSet "

bsFileSections.DataSource = From ncfps In NCFile.NCFilePartSet Order By ncfps.Sort Select ncfps 

or like this

bsFileSections.DataSource = NCFile.NCFilePartSet.OrderBy(Function(ncfps) ncfps.Sort)

where "Sort" is a column in NCFilePartSet

Updates on entities continue working and reflects back to the database

Upvotes: 1

Aaron Young
Aaron Young

Reputation: 261

I recently struggled with this same issue; it seems that the IQueryable interface doesn't provide enough information for the DataViewGrid to know how to sort the data automatically; so you have to either repackage your collection from the Entity source using something it can use or do what I did and handle the sorting functionality manually:

      private void myDataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
  {
     DataGridViewColumn column = myDataGridView.Columns[e.ColumnIndex];

     _isSortAscending = (_sortColumn == null || _isSortAscending == false);

     string direction = _isSortAscending ? "ASC" : "DESC";

     myBindingSource.DataSource = _context.MyEntities.OrderBy(
        string.Format("it.{0} {1}", column.DataPropertyName, direction)).ToList();

     if (_sortColumn != null) _sortColumn.HeaderCell.SortGlyphDirection = SortOrder.None;
     column.HeaderCell.SortGlyphDirection = _isSortAscending ? SortOrder.Ascending : SortOrder.Descending;
     _sortColumn = column;
  }

I hope that helps.

Upvotes: 14

Related Questions