Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 790
  • Last Modified:

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

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
BugRaptor
Asked:
BugRaptor
  • 2
1 Solution
 
BugRaptorAuthor Commented:
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
 
BugRaptorAuthor Commented:
Any other idea to make the automatic sorting of the dataGridView faster would be welcome !
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

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.

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now