Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Automatic Column Sorting using LiNQ in C#

Posted on 2011-10-14
5
Medium Priority
?
1,580 Views
Last Modified: 2013-11-11
HI,

I am using a DataGridView to display data from two tables in my typed dataset.

I am creating the combined data using a LINQ query.

I am then assigning the datasource property of the DataGridView to the results of the LINQ Query.

At this point the data displays fine, however, the automatic sorting capabilities of the DataGridView columns are not available. The sorting returns when I use a standard datatable to display the data.

Code Sample Below:

myBindingSource.DataSource = myLINQQuery;                              
myDataGridView.DataSource = myBindingSource;

Thanks in advance for any suggestions.
0
Comment
Question by:Ibs
5 Comments
 
LVL 7

Expert Comment

by:Rahul_Gade
ID: 36967607
It is not possible in this way, but you can wrap up your result in to SortableBindingList<> implementation class and achive the same this that you want to.

-Rahul
0
 
LVL 1

Accepted Solution

by:
TJCombos earned 1000 total points
ID: 37275724
0
 
LVL 15

Assisted Solution

by:Navneet
Navneet earned 1000 total points
ID: 37302780
Hi!

This should work nice for sorting.

Since your LINQ List needs to be Bindable.
Simply instead of ToList()  write AdvancedList()


using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

namespace SortedList
{
    public  class AdvancedList<T> : BindingList<T>
    {



        protected override bool SupportsSearchingCore
        {
            get
            {
                return true;
            }
        }

        protected override bool SupportsSortingCore
        {
            get
            {
                return true;
            }
        }

        bool isSortedValue;
        protected override bool IsSortedCore
        {
            get
            {
                return isSortedValue;
            }
        }

        private ArrayList sortedList;
        private ArrayList unsortedItems;

        protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
        {
            sortedList = new ArrayList();

            // Check to see if the property type we are sorting by implements
            // the IComparable interface.
            Type interfaceType = prop.PropertyType.GetInterface("IComparable");

            if (interfaceType == null && prop.PropertyType.IsValueType)
            {
                Type underlyingType = Nullable.GetUnderlyingType(prop.PropertyType);
                // Nullable.GetUnderlyingType only returns a non-null value if the    
                // supplied type was indeed a nullable type.     
                if (underlyingType != null)
                    interfaceType = underlyingType.GetInterface("IComparable");
            }

            if (interfaceType != null)
            {


                unsortedItems = new ArrayList(this.Count);

                // Loop through each item, adding it the the sortedItems ArrayList.
                foreach (Object item in this.Items)
                {
                    sortedList.Add(prop.GetValue(item));
                    unsortedItems.Add(item);
                }
                // Call Sort on the ArrayList.
                sortedList.Sort();
                T temp;

                // Check the sort direction and then copy the sorted items
                // back into the list.
                if (direction == ListSortDirection.Descending)
                    sortedList.Reverse();

                for (int i = 0; i < this.Count; i++)
                {
                    int position = Find(prop.Name, sortedList[i]);
                    if (position != i)
                    {
                        temp = this[i];
                        this[i] = this[position];
                        this[position] = temp;
                    }
                }
                isSortedValue = true;

                // If so, set the SortPropertyValue and SortDirectionValue.
                sortPropertyValue = prop;
                sortDirectionValue = direction;

                // Raise the ListChanged event so bound controls refresh their
                // values.
                OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, 1));

            }
            else
            {
                // If the property type does not implement IComparable, let the user
                // know.
                throw new NotSupportedException("Cannot sort by " + prop.Name +
                    ". This" + prop.PropertyType.ToString() +
                    " does not implement IComparable");
            }

        }

        ListSortDirection sortDirectionValue;
        PropertyDescriptor sortPropertyValue;
        protected override PropertyDescriptor SortPropertyCore
        {
            get { return sortPropertyValue; }
        }

        protected override ListSortDirection SortDirectionCore
        {
            get { return sortDirectionValue; }
        }

        public int Find(string property, object key)
        {
            // Check the properties for a property with the specified name.
            PropertyDescriptorCollection properties =
                TypeDescriptor.GetProperties(typeof(T));
            PropertyDescriptor prop = properties.Find(property, true);

            // If there is not a match, return -1 otherwise pass search to
            // FindCore method.
            if (prop == null)
                return -1;
            else
                return FindCore(prop, key);
        }

        protected override int FindCore(PropertyDescriptor prop, object key)
        {
            // Get the property info for the specified property.
            PropertyInfo propInfo = typeof(T).GetProperty(prop.Name);
            T item;

            if (key != null)
            {
                // Loop through the items to see if the key
                // value matches the property value.
                for (int i = 0; i < Count; ++i)
                {
                    item = (T)Items[i];
                    if (propInfo.GetValue(item, null).Equals(key))
                        return i;
                }
            }
            return -1;

        }

    }

    public class SortableBindingList<T> : BindingList<T>
    {
        private bool m_Sorted = false;
        private ListSortDirection m_SortDirection = ListSortDirection.Ascending;
        private PropertyDescriptor m_SortProperty = null;

        protected override bool SupportsSortingCore
        {
            get
            {
                return true;
            }
        }

        protected override bool IsSortedCore
        {
            get
            {
                return m_Sorted;
            }
        }

        protected override ListSortDirection SortDirectionCore
        {
            get
            {
                return m_SortDirection;
            }
        }

        protected override PropertyDescriptor SortPropertyCore
        {
            get
            {
                return m_SortProperty;
            }
        }

        protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
        {
            m_SortDirection = direction;
            m_SortProperty = prop;
            var listRef = this.Items as List<T>;
            if (listRef == null)
                return;
            var comparer = new SortComparer<T>(prop, direction);
            m_Sorted = true;

            listRef.Sort(comparer);
            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));

        }
    }

    internal class SortComparer<T> : IComparer<T>
    {
        private PropertyDescriptor m_PropDesc = null;
        private ListSortDirection m_Direction = ListSortDirection.Ascending;

        public SortComparer(PropertyDescriptor propDesc, ListSortDirection direction)
        {
            m_PropDesc = propDesc;
            m_Direction = direction;
        }

        int IComparer<T>.Compare(T x, T y)
        {
            object xValue = m_PropDesc.GetValue(x);
            object yValue = m_PropDesc.GetValue(y);
            return CompareValues(xValue, yValue, m_Direction);
        }

        private int CompareValues(object xValue, object yValue, ListSortDirection direction)
        {
            if (xValue == null & yValue == null) { return 0; }
            else if (xValue == null) { return -1; }
            else if (yValue == null) { return 1; }

            int retValue = 0;
            if (xValue is IComparable) //can ask the x value  
            {
                retValue = ((IComparable)xValue).CompareTo(yValue);
            }
            else if (yValue is IComparable) //can ask the y value  
            {
                retValue = ((IComparable)yValue).CompareTo(xValue);
            }
            //not comparable, compare string representations  
            else if (!xValue.Equals(yValue))
            {
                retValue = xValue.ToString().CompareTo(yValue.ToString());
            }
            if (direction == ListSortDirection.Ascending)
                return retValue;
            else
                return retValue * -1;
        }
    }

    /// <summary>
    /// Extension Module to Allow the Linq Query to return ToAdvancedList().
    /// </summary>
    public static class Extensions
    {
       /// <summary>
       /// Extension Class for IEnumerable to allow the conversion of output to Advancedlist<TSource>
       /// </summary>
       /// <typeparam name="TSource">Type Of Business Object</typeparam>
       /// <param name="source">Collection of IEnumerable </param>
       /// <returns></returns>
        public static AdvancedList<TSource> ToAdvancedList<TSource>(this IEnumerable<TSource> source)
        {
            AdvancedList<TSource> MyList = new AdvancedList<TSource>();
            try
            {
                foreach (var item in source)
                {
                    MyList.Add(item);
                }
                return MyList;
            }
            catch (Exception)
            {
                throw new Exception("Error converting AdvancedList");
            }

        }

        public static SortableBindingList<TSource> ToSortableList<TSource>(this IEnumerable<TSource> source)
        {
            SortableBindingList<TSource> MyList = new SortableBindingList<TSource>();
            try
            {
                foreach (var item in source)
                {
                    MyList.Add(item);
                }
                return MyList;
            }
            catch (Exception)
            {
                throw new Exception("Error converting AdvancedList");
            }

        }
    }
}

Open in new window


Thanks!
0
 

Expert Comment

by:BugRaptor
ID: 39215689
I tried to implement the assisted solution by adding a Project SortedList with the navneethedge's code to my solution. (Referencing it and using its SortedList namespace).

My LiNQ query is now written like this:
                
var query = from Order in context.Orders
            where Order.Processed == true
            select new { Order.X, Order.Y, Order.Z };
var results = query.AdvancedList(); // instead of ToList()
dataGridView1.DataSource = results;

Open in new window

But I got the following error when generating the solution:

Error      1      'System.Linq.IQueryable<AnonymousType#1>' does not contain a definition for 'AdvancedList' and no extension method 'AdvancedList' accepting a first argument of type 'System.Linq.IQueryable<AnonymousType#1>' has been found (is a using directive or an assembly reference missing ?)

(I tried to use a non anonymous class for the result but I got the same error).

What am I doing wrong ?

Do I have to update the Extension Module code in any way to match the result type ?

If so, how ?

Thank you for your help. (I'm new to c#)
0
 

Expert Comment

by:BugRaptor
ID: 39221866
Huh !

In the solution, should have read "Simply instead of ToList()  write ToAdvancedList()" instead of "Simply instead of ToList()  write AdvancedList()".

That misled me.

LiNQ correct code:
var query = from Order in context.Orders
            where Order.Processed == true
            select new { Order.X, Order.Y, Order.Z };
var results = query.ToAdvancedList(); // instead of ToList()
dataGridView1.DataSource = results;

Open in new window

0

Featured Post

Configuration Guide and Best Practices

Read the guide to learn how to orchestrate Data ONTAP, create application-consistent backups and enable fast recovery from NetApp storage snapshots. Version 9.5 also contains performance and scalability enhancements to meet the needs of the largest enterprise environments.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
This article shows how to deploy dynamic backgrounds to computers depending on the aspect ratio of display
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Is your data getting by on basic protection measures? In today’s climate of debilitating malware and ransomware—like WannaCry—that may not be enough. You need to establish more than basics, like a recovery plan that protects both data and endpoints.…
Suggested Courses

864 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question