简体   繁体   中英

Program hangs while trying to sort ListView WinForms C# using builtin .Sort() method (only Visual Studio is affected)

I'm having some strange problem with ListView that refuses to sort itself properly. I'm using this code on 99% of ListView's in my program and they do work fine. However for one ListView (and it used to work on it) it refuses to work hanging program. When I added LineBreaks all over both methods. It reaches ListViewColumnSorter.columnClick(listViewKlienci, ref lvwColumnSorterKlienci, sender, e, headerIcons); then goes thru the code to the varListView.Sort(); and it stops here.. never reaches end of method. ListView is very simple with 2 columns and some colors.

private void listViewKlienci_ColumnClick(object sender, ColumnClickEventArgs e) {
        ListViewColumnSorter.columnClick(listViewKlienci, ref lvwColumnSorterKlienci, sender, e, headerIcons);
        ListViewHelper.listViewResize(listViewKlienci);
}

public static void columnClick(ListView varListView, ref ListViewColumnSorter lvwColumnSorter, object sender, ColumnClickEventArgs e, ImageList headerImages) {
        //get list view header
        IntPtr hHeader = SendMessage(varListView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
        SendMessage(hHeader, HDM_SETIMAGELIST, IntPtr.Zero, headerImages.Handle);
        SortOrder Order = SortOrder.Descending;
        //format icons
        HDITEM hd = new HDITEM {
                                   mask = HDI_IMAGE | HDI_FORMAT
                               };
        for (int i = 0; i < varListView.Columns.Count; i++) {
            //    if (i != e.Column) {
            hd.fmt = HDF_LEFT | HDF_STRING;
            hd.iImage = -1;
            SendMessage(hHeader, HDM_SETITEM, new IntPtr(i), ref hd);
            //    }
        }
        hd.fmt = HDF_LEFT | HDF_STRING | HDF_BITMAP_ON_RIGHT;
        ListViewHelper.enableDoubleBuffer(varListView);
        if (Order != SortOrder.None) {
            hd.fmt |= HDF_IMAGE;
        }
        if (e.Column == lvwColumnSorter.SortColumn) {
            if (lvwColumnSorter.Order == SortOrder.Ascending) {
                hd.iImage = 0;
                lvwColumnSorter.Order = SortOrder.Descending;
            } else {
                hd.iImage = 1;
                lvwColumnSorter.Order = SortOrder.Ascending;
            }
        } else {
            hd.iImage = 1;
            lvwColumnSorter.SortColumn = e.Column;
            lvwColumnSorter.Order = SortOrder.Ascending;
        }
        SendMessage(hHeader, HDM_SETITEM, new IntPtr(e.Column), ref hd);
        varListView.Sort();
    }

And Compare is executed a lot during Sort().

    /// <summary>
    ///   This method is inherited from the IComparer interface.  It compares the two objects passed using a case insensitive comparison.
    /// </summary>
    /// <param name = "x">First object to be compared</param>
    /// <param name = "y">Second object to be compared</param>
    /// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>

 public int Compare(object x, object y) {
        int compareResult;
        var listviewX = (ListViewItem) x;
        var listviewY = (ListViewItem) y;
        string s1 = listviewX.SubItems.Count > ColumnToSort ? listviewX.SubItems[ColumnToSort].Text : String.Empty;
        string s2 = listviewY.SubItems.Count > ColumnToSort ? listviewY.SubItems[ColumnToSort].Text : String.Empty;
        int i1;
        int i2;
        DateTime date1;
        DateTime date2;
        decimal d1;
        decimal d2;

        if (int.TryParse(s1, out i1) && int.TryParse(s2, out i2)) {
            compareResult = ObjectCompare.Compare(i1, i2);
        } else if (DateTime.TryParse(s1, out date1) && DateTime.TryParse(s2, out date2)) {
            compareResult = ObjectCompare.Compare(date1, date2);
        } else if (Locale.returnDecimalFromZl(s1, out d1) && Locale.returnDecimalFromZl(s2, out d2)) {
            compareResult = ObjectCompare.Compare(d1, d2);
        } else {
            compareResult = ObjectCompare.Compare(s1, s2);
        }
        // Calculate correct return value based on object comparison
        if (OrderOfSort == SortOrder.Ascending) {
            // Ascending sort is selected, return normal result of compare operation
            return compareResult;
        } else if (OrderOfSort == SortOrder.Descending) {
            // Descending sort is selected, return negative result of compare operation
            return (-compareResult);
        } else {
            // Return '0' to indicate they are equal
            return 0;
        }
    }

If i change code a bit and remove all those if's and leave only one compare it returns results instantly.

        //if (int.TryParse(s1, out i1) && int.TryParse(s2, out i2)) {
        //    compareResult = ObjectCompare.Compare(i1, i2);
        //} else if (DateTime.TryParse(s1, out date1) && DateTime.TryParse(s2, out date2)) {
        //    compareResult = ObjectCompare.Compare(date1, date2);
        //} else if (Locale.returnDecimalFromZl(s1, out d1) && Locale.returnDecimalFromZl(s2, out d2)) {
        //    compareResult = ObjectCompare.Compare(d1, d2);
        //} else {
            compareResult = ObjectCompare.Compare(s1, s2);
       // }

It seems this is the reason... but it works fine outside of Visual Studio, just in Visual Studio it's causing great slowdown.

I further started adding more compareResults and only last one is causing the slowdown:

 public static bool returnDecimalFromZl(string dataToCheck, out decimal value) {
        if (dataToCheck.Trim() != "") { // && dataToCheck.Contains(" zł")) {
            try {
                value = Decimal.Parse(dataToCheck.Trim(), NumberStyles.Number | NumberStyles.AllowCurrencySymbol);
                return true;
            } catch {
                value = 0m;
                return false;
            }
        }
        value = 0m;
        return false;
    }

If I change it to:

    public static bool returnDecimalFromCurrency(string dataToCheck, out decimal value) {
        if ((dataToCheck.Trim() != "")  && (dataToCheck.Contains(" zł"))) {
            try {
                value = Decimal.Parse(dataToCheck.Trim(), NumberStyles.Number | NumberStyles.AllowCurrencySymbol);
                return true;
            } catch {
                value = 0m;
                return false;
            }
        }
        value = 0m;
        return false;
    }

It started working instantly.. which is only && (dataToCheck.Contains(" zł")) more in method. WEIRD STUFF!

EDIT1: Funny thing after I left it running for 5-10 minutes it returned from Sort successfully...

EDIT2. Sorting using 1st column works. 2nd column holds names of people (1200~ names)

EDIT3. Sorting outside of Visual Studio works fine (I went to BIN directory in project and executed my app - sorting in 1sec). So it seems only Visual Studio is affected. I even put my old hdd into my computer with different (same version) Visual Studio installed and the issue was still there.

EDIT4. If I start it up with PROFILER such as RedGate ANTS profiler from withing Visual Studio problem doesn't show up and ListView Sorting is very fast... $#^$*$#%

You found out why the TryParse() method was added in .NET version 2.0. Switch to the Output window to observe the thousands of 'first chance' exception notification messages. Exception handling becomes really expensive when a debugger is attached.

Found out that after I changed method from

 public static bool returnDecimalFromZl(string dataToCheck, out decimal value) {
        if (dataToCheck.Trim() != "") { 
            try {
                value = Decimal.Parse(dataToCheck.Trim(), NumberStyles.Number | NumberStyles.AllowCurrencySymbol);
                return true;
            } catch {
                value = 0m;
                return false;
            }
        }
        value = 0m;
        return false;
    }

If I change it to:

    public static bool returnDecimalFromZl(string dataToCheck, out decimal value) {
        if ((dataToCheck.Trim() != "")  && (dataToCheck.Contains(" zł"))) {
            try {
                value = Decimal.Parse(dataToCheck.Trim(), NumberStyles.Number | NumberStyles.AllowCurrencySymbol);
                return true;
            } catch {
                value = 0m;
                return false;
            }
        }
        value = 0m;
        return false;
    }

program started to work correctly in Visual Studio too. Why would it behave normally when used outside of Visual Studio and inside I have no clue. Speed difference is 5-10 minutes on 1200 objects :/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM