Solved

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

Posted on 2013-06-06
2
757 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

Migrating Your Company's PCs

To keep pace with competitors, businesses must keep employees productive, and that means providing them with the latest technology. This document provides the tips and tricks you need to help you migrate an outdated PC fleet to new desktops, laptops, and tablets.

Question has a verified solution.

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

This article aims to explain the working of CircularLogArchiver. This tool was designed to solve the buildup of log file in cases where systems do not support circular logging or where circular logging is not enabled
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.
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 …

803 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