2

I would like to do "sorting" under Datagridview ColumnHeaderMouseClick. Accending or Decending should need to be automatic, selected column value automatic.

I gone through many websites and tried some options but I could not be able to achieve my goal.

private void lst_Install_Item_Main_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
    try
    {
        DataGridViewColumn newColumn = lst_Install_Item_Main.Columns[e.ColumnIndex];
        List<test> temp = (List<test>)lst_Install_Item_Main.DataSource;

        //var newList = temp.OrderBy(m => m.feet).ToList();
        //var newList = temp.AsQueryable().OrderBy(m => m.feet).ToList();
        temp.Sort((m1, m2) => m1.feet.CompareTo(m2.feet));

        lst_Install_Item_Main.DataSource = temp;
        lst_Install_Item_Main.Refresh();
    }
    catch (Exception ex)
    {
        MessageBox.Show("There was an error bringing sorting \n" + ex.Message, "Testing", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

Above code "sorting" the list on "feet" column but

  1. I would like to pass the columnname which user clicked, is that possible ?

I have input like (1', 21', 123', 5', 10') Above code sorting the list like >> (1', 10', 123', 21', 5')

  1. But I want output like >> (1', 5', 10', 21', 123') Is that possible to achieve ?

  2. How to achieve Ascending or Descending here (I mean while I clicked first time it will do Ascending and while click on same column second time it should need to do Descending)

Your suggestionshelp are greatly appreciated.

5
  • Your second "question" is because the data type is string instead of a number. Make your numeric values actual numeric values and the system will sort them the way you expect. Commented Feb 16, 2016 at 12:20
  • String vs Int-Sorting ... Commented Feb 16, 2016 at 12:20
  • You don't have input like (1', 21', 123', 5', 10'), but more like new [] { "1'", "21'", "123'", "5'", "10'" }, right? Commented Feb 16, 2016 at 12:20
  • 1) "Is this possible?" Yes. 2) "Is that possible to achieve?" Yes. 3) You can't do it with a single LINQ statement. You'll need to conditionally add filtering to your query. To answer that question, you haven't shown any solid attempt to answer it yourself. Commented Feb 16, 2016 at 12:23
  • @krillgar .. how to achieve first question, if you can give some example it will be very helpful. Commented Feb 16, 2016 at 14:02

5 Answers 5

2

If you don't have negative values, then to sort as you want you need either to parse values as numeric or simply pad them:

temp.Sort((m1, m2) => m1.feet.PadLeft(2).CompareTo(m2.feet.PadLeft(2)));

When comparing strings "1", "5" and "10" this will be comparing " 1", " 5" and "10" instead (notice empty space, which is less than 0 character), making them sorted in the right order.

Make sure to chose number big enough to cover padding to the longest number.

Sign up to request clarification or add additional context in comments.

7 Comments

Wow, what a dirty hack to get integer-based sorting.
@HimBromBeere, might be faster than padding+parsing, measure it ;)
Actually pretty neat, this way you won't have to remove the ' character from the text to sort the values.
@Sinatr .. sorry but this giving me same result which I am getting earlier.
@Hardik, using PadLeft(4) (to cover longest number which is 123 + character ') ?
|
2

You need to sort the values of feet as integers. To do this, you first need to remove the feet-symbol (') and afterwards parse the value to an int (temporarily, the value is still stored as a string).

This should do the trick:

temp.Sort((m1, m2) => int.Parse(m1.feet.Replace("'", "")).CompareTo(int.Parse(m2.feet.Replace("'", ""))));

Also, I would recommend that you don't store the feet-symbol in the value, and instead use some kind of formatting to include it, when showing the values in the Grid. That way you can avoid these kinds of conversions and comparisons, each time you need to use the values.

2 Comments

It's giving me an error " Cannot convert lambda expression to type 'System.Collections.Generic.IComparer<UI.CloseoutCalcForm.test>' because it is not a delegate type"
@Hardik, I see I have used some variable names a little different than your example. I will edit my answer to fix that, but can you show the structure of your test class? You might missing some using statements.
2

You have to convert your strings to integer-values as strings are differently ordered (lexicographically 10 comes before 2). Furtheremore as your input contains '-characters you have to delete them first using String.Trim('\'').

temp.Sort((m1, m2) => Convert.ToInt32(m1.feet.Trim('\'')).CompareTo(Convert.ToInt(m2.feet.Trim('\''))));

Alternativly you may also use Linq-OrderBy:

temp = temp.OrderBy(x => Convert.ToInt32(x.feet.Trim('\''))).ToList();

And OrderByDescending if in descending-order.

8 Comments

It seems like the input is "4'" so this code would cause an "Input string was not in a correct format." exception.
Indeed, I trim the characters now
this does compile now +1 :)
@HimBromBeere .. It's giving me an error " Cannot convert lambda expression to type 'System.Collections.Generic.IComparer<UI.CloseoutCalcForm.test>' because it is not a delegate type"
Indeed, you cannot cast an string directly to int., you have to either use Convert.ToInt32 or int.Parse.
|
0

UPDATED for question # 3, added trigger for sort order

I would suggest you to use ICoparer in such way

public class TestComparer : IComparer<test>
{
    bool isAscending;

    public TestComparer(bool isAscendingOrder)
    {
        isAscending = isAscendingOrder;
    }

    int IComparer<test>.Compare(test a, test b)
    {
        int c1 = IntFromStr(a.feet);
        int c2 = IntFromStr(b.feet);
        int res;
        res = (c1 > c2) ? 1 : (c1 < c2) ? -1 : 0;
        return isAscending ? res : -res;
    }

    int IntFromStr(string s)
    {
        int result;
        return (int.TryParse(s.Replace("'", ""), out result)) ? result : int.MaxValue;
    }
}

this comparer will move not valid items to the end of the sorted list, also you will be able to change your sort behaviour easily, you will call it like below

    List < test > lst = new List<test>();
    // It will be your property to Trigger value each time you click
    // (sortOrderTrigger = !sortOrderTrigger)
    bool sortOrderTrigger = true;

    lst.Add(new test { feet = "1'" });
    lst.Add(new test { feet = "21'" });
    lst.Add(new test { feet = "123'" });
    lst.Add(new test { feet = "5'" });
    lst.Add(new test { feet = "10'" });
    lst.Add(new test { feet = "15'" });
    lst.Add(new test { feet = "jj'" });
    lst.Add(new test { feet = "ff'" });

    lst.Sort(new TestComparer(sortOrderTrigger));

2 Comments

second problem is function icompare it's hard coded "feet" column... I have multiple columns..
I've made test console app and copied code from it, and it definitely works, as you can see we pass test object, not feet column, you can change Compare method to whatever you want
0

Thanks for all your help and Direction. I have fixed my requirements as like below, Hope this help to someone like me :)

1. Created list which contains the same columns as the columns dataproperty.

public class sortList
        {
            public string Layer { get; set; }
            public string mlenth { get; set; }
            public string diameter { get; set; }
            public string subtypecd { get; set; }
            public string coatingtype { get; set; }
            public string year { get; set; }
            public string gisid { get; set; }
            public string taxdistrict { get; set; }
            public string lengthsource { get; set; }
            public string shapelen { get; set; }
            public string feet { get; set; }    

            public sortList()
            {
                this.Layer = ListSortDirection.Ascending.ToString();
                this.mlenth = ListSortDirection.Ascending.ToString();
                this.feet = ListSortDirection.Ascending.ToString();
                this.diameter = ListSortDirection.Ascending.ToString();
                this.subtypecd = ListSortDirection.Ascending.ToString();
                this.coatingtype = ListSortDirection.Ascending.ToString();
                this.year = ListSortDirection.Ascending.ToString();
                this.gisid = ListSortDirection.Ascending.ToString();
                this.taxdistrict = ListSortDirection.Ascending.ToString();
                this.lengthsource = ListSortDirection.Ascending.ToString();
                this.shapelen = ListSortDirection.Ascending.ToString();
            }
        }

2. Written code on ColumnHeaderMouseClick event and order function

private void lst_Install_Item_Main_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            try
            {
                //Get Column which clicked
                DataGridViewColumn newColumn = lst_Install_Item_Main.Columns[e.ColumnIndex];
                //Get Values from DataGrid
                List<test> temp = (List<test>)lst_Install_Item_Main.DataSource;

                //Get the sorting order for that column
                string orderby = GetOrder(newColumn.DataPropertyName);

                if (orderby == ListSortDirection.Ascending.ToString()) //Ascending
                {
                    if (newColumn.DataPropertyName == "feet") //Feet column sort with double value and required trim
                    {
                        temp = temp.OrderBy(x => Convert.ToDouble(x.feet.Trim('\''))).ToList();
                    }
                    else if (newColumn.DataPropertyName == "shapelen") //Shapelen column sort with double value and required trim
                    {
                        temp = temp.OrderBy(x => Convert.ToDouble(x.shapelen.Trim('\''))).ToList();
                    }
                    else ///other columns having string value only.
                    {
                        temp = temp.OrderBy(x => x.GetType().GetProperty(newColumn.DataPropertyName).GetValue(x, null)).ToList();
                    }
                }
                else // Descending 
                {
                    if (newColumn.DataPropertyName == "feet") //Feet column sort with double value and required trim
                    {
                        temp = temp.OrderByDescending(x => Convert.ToDouble(x.feet.Trim('\''))).ToList();
                    }
                    else if (newColumn.DataPropertyName == "shapelen")  //Shapelen column sort with double value and required trim
                    {
                        temp = temp.OrderByDescending(x => Convert.ToDouble(x.shapelen.Trim('\''))).ToList();
                    }
                    else //other columns having string value only.
                    {
                        temp = temp.OrderByDescending(y => y.GetType().GetProperty(newColumn.DataPropertyName).GetValue(y, null)).ToList();
                    }
                }
                lst_Install_Item_Main.DataSource = temp;
                lst_Install_Item_Main.Refresh();
            }
            catch (Exception ex)
            {
                MessageBox.Show("There was an error while sorting \n" + ex.Message, "Closeout Calculator", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private string GetOrder(string columnName)
        {
            //Store the each coulmn(Ascending/Descending) values to make it dynamic 
            string ord = sortOrder[0].GetType().GetProperty(columnName).GetValue(sortOrder[0], null).ToString();
            if (ord == ListSortDirection.Ascending.ToString())
            {
                sortOrder[0].GetType().GetProperty(columnName).SetValue(sortOrder[0], ListSortDirection.Descending.ToString(), null);
            }
            else
            { sortOrder[0].GetType().GetProperty(columnName).SetValue(sortOrder[0], ListSortDirection.Ascending.ToString(), null); }
            return ord;
        }

3. sortoder list initialize and obj declared at Constructor.

Private List<sortList> sortOrder = new List<sortList>();

sortOrder.Add(new sortList());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.