Solved

Why does "Automatic Column Sorting Using LiNQ" solution appear so slow ???

Posted on 2013-06-06
2
763 Views
Last Modified: 2013-06-06
I have implemented the Assisted solution  ID: 37302780  proposed in the thread Automatic Column Sorting using LiNQ in C# (ID 27396517)

It works, but I was wondering why the sorting of the dataGridView appears so slow ?!?!

(~12 seconds to sort a List containing only 200 items !!!!!)

I changed a bit the proposed code expecting a faster sorting by suppressing the need to call the Find method in the for loop of the ApplySortCore overridden method.

Here is my AdvancedList modified code: (The overridden ApplySortCore method has been modified)

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.
                int idx = 0;
                foreach (Object item in this.Items)
                {
                    sortedList.Add(new SortedItem { val = (IComparable)(prop.GetValue(item)), pos = idx});
                    unsortedItems.Add(item);
                    idx++;
                }
                // Call Sort on the ArrayList.
                sortedList.Sort();

                // 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 = ((SortedItem)sortedList[i]).pos;
                    this[i] = (T)unsortedItems[position];
                }
                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; }
        }

    }

    internal class SortedItem : IComparable
    {
        public IComparable val { get; set; }
        public int pos { get; set; }

        public int CompareTo(object obj)
        {
            if (obj is SortedItem)
            {
                return this.val.CompareTo(((SortedItem)obj).val);
            }
            else
            {
                throw new InvalidCastException();
            }
        }

    }

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

        }
    }
}

Open in new window


Surprisingly, this modified code is always so slow !!!

Why does it require so much time to sort the binded dataGridView with only 200 items ???

It seems (when debugging step by step) that the the sorting of the ArrayList sortedList containing the values of the sorting column is very fast:
sortedList.Sort();

Open in new window

But the final for loop ordering the AdvancedList items (bind to the dataGridView) appears to require a lot of time:
for (int i = 0; i < this.Count; i++)
{
       int position = ((SortedItem)sortedList[i]).pos;
       T item = (T)unsortedItems[position];
       this[i] = item;  // This instruction costs 60ms !!! Why ???
}

Open in new window

This for loop requires 12 seconds to execute (with 200 items in the AdvancedList) !

Can you give me an explanation of this extremely (and not acceptable) slow behavior ?

How could we make it much faster ?

Here is my LiNQ query and the binding code to the dataGridView:
var query = from w in context.Weighings
            where w.Processed == true
            orderby w.OF
            select new { w.Id, w.DTEnd, w.OF, w.Product, w.SetWeight, w.NetWeight, w.Status, w.UserName };
var results = query.ToAdvancedList();
dataGridView.DataSource = results;

Open in new window

0
Comment
Question by:BugRaptor
  • 2
2 Comments
 

Accepted Solution

by:
BugRaptor earned 0 total points
ID: 39225451
I partly understood the reason of the slow automatic sorting:

Had to set the RaiseListChangedEvents property of my AdvancedList to false to prevent each item change in the internal for loop to raise an event during sorting !

var query = from w in context.Weighings
            where w.Processed == true
            orderby w.OF
            select new { w.Id, w.DTEnd, w.OF, w.Product, w.SetWeight, w.NetWeight, w.Status, w.UserName };
var results = query.ToAdvancedList();
dataGridView.DataSource = results;
results.RaiseListChangedEvents = false; // Do not raise ListChanged events on each change to the list.
                                       // (IMPORTANT in order to make the automatic sorting faster)

Open in new window

It's now faster, but not as fast as I would expect... :-(
0
 

Author Closing Comment

by:BugRaptor
ID: 39225454
Any other idea to make the automatic sorting of the dataGridView faster would be welcome !
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

This article introduced a TextBox that supports transparent background.   Introduction TextBox is the most widely used control component in GUI design. Most GUI controls do not support transparent background and more or less do not have the…
This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

860 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