Программа зависает при попытке сортировки ListView WinForms С# с использованием встроенного метода .Sort() (затрагивается только Visual Studio) - c#


1

У меня возникла какая-то странная проблема с ListView, которая отказывается сортировать себя должным образом. Я использую этот код на 99% ListView в моей программе, и они отлично работают. Однако для одного ListView (и он работал над ним) он отказывается работать под висячей программой. Когда я добавил LineBreaks по обоим методам. Он достигает ListViewColumnSorter.columnClick(listViewKlienci, ref lvwColumnSorterKlienci, sender, e, headerIcons);, затем переходит через код в varListView.Sort(); и останавливается здесь.. никогда не достигает конца метода. ListView очень просто с двумя столбцами и некоторыми цветами.

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();
    }

И Compare выполняется во время 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 (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);
       // }

Кажется, это причина... но он отлично работает за пределами Visual Studio, только в Visual Studio, что вызывает значительное замедление.

Я также начал добавлять дополнительные compareResults и только последний из них вызывает Замедление:

 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;
    }

Если я изменил его на:

    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;
    }

Он начал работать мгновенно, что только && (dataToCheck.Contains(" zł")) больше в методе. СТРАННЫЕ ВЕЩИ!

EDIT1: Забавная штука после того, как я оставил ее в течение 5-10 минут, она вернулась из Сортировки успешно...

EDIT2. Сортировка с использованием 1-го столбца. 2-й столбец содержит имена людей (имена 1200 ~)

EDIT3. Сортировка вне Visual Studio отлично работает (я пошел в каталог BIN в проекте и выполнил мое приложение - сортировка в 1 сек.). Таким образом, это похоже только на Visual Studio. Я даже поставил свой старый hdd на свой компьютер с другой (той же версией) Visual Studio, и проблема все еще была там.

EDIT4. Если я запустил его с помощью PROFILER, например, профилировщик RedGate ANTS из-за проблемы с Visual Studio, не появляется, и сортировка списков очень быстрая... $# ^ $* $#%

  •  5
  •  2
  • 8 фев 2020 2020-02-08 08:05:59

2 ответа

0

Узнал, что после того, как я изменил метод из

 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;
    }

Если я изменил его на:

    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;
    }
Программа

начала корректно работать и в Visual Studio. Почему это должно вести себя нормально, когда используется вне Visual Studio и внутри я не знаю. Разница в скорости составляет 5-10 минут на 1200 объектов:/

  • 8 фев 2020 2020-02-08 08:06:00
1

Вы узнали, почему метод TryParse() был добавлен в .NET версии 2.0. Переключитесь в окно "Вывод", чтобы наблюдать тысячи уведомлений об уведомлениях о "первой случайности". Обработка исключений становится очень дорогостоящей при подключении отладчика.