Есть ли способ фильтрации и ограничения строк в DataGridView? - PullRequest
0 голосов
/ 11 октября 2019

Я пишу программу продаж, для этого мне нужно окно просмотра, где пользователь может просмотреть все продукты, которые он имеет для продажи. Это может означать тысячи продуктов, поэтому фильтрация - единственный путь. Я обнаружил, что самый быстрый способ фильтрации - заполнить DataTable продуктами (а не заполнять DataGridView напрямую, что было моим первым решением) и использовать его возможности фильтрации.

private void nameTB_TextChanged(object sender, EventArgs e)
{
    browseDataTable.DefaultView.RowFilter = "name LIKE '%" + nameTB.Text + "%'";
}

Это позволяет получить работусделано только для визуализации того, что ищет менеджер по продажам (отныне: пользователь), и это отлично работало для примерно 300 строк (продуктов). Увеличение этого показателя до 10000 продуктов (что не только для проверки текущей базы данных из магазина) и время загрузки выросли в геометрической прогрессии с 1 секунды до 40, что в условиях продаж недопустимо.

Продукты находятся вБаза данных MySQL в фоновом режиме. Запрос и сохранение его в DataTable занимает менее секунды, что приемлемо для 10000 продуктов, проблемы возникают, когда я пытаюсь его визуализировать. Простое:

datagridview1.DataSource = browseDataTable;

Требуется около 4 секунд, что было бы приемлемо, но для этого приложения мне нужно добавить стили к моим 6 столбцам + заголовок (все столбцы имеют разные шрифты, некоторые переносы, некоторыеи т. д.), что увеличивает время загрузки примерно до 40 секунд, но без стилей на сенсорном мониторе низкого качества в хорошо освещенной комнате пользователь не сможет видеть ряды. Ограничение - это был путь, я не нашел лучшего решения, чем использовать что-то вроде этого

browseDataTable.AsEnumerable().Take(100).CopyToDataTable(visibleDataTable, LoadOption.OverwriteChanges);
datagridview1.DataSource = visibleDataTable;

Это делает его визуализацию снова 1 секунду.

Моя проблемаэто когда я пытаюсь использовать ограничение вместе с отфильтрованными продуктами (визуализируйте только первые 100 отфильтрованных строк). Попытка объединить, какой DataTable должен быть источником данных DataGridView, следующим образом:

browseDataTable.AsEnumerable().Take(100).CopyToDataTable(visibleDataTable, LoadOption.OverwriteChanges); //done once somewhere

    private void nameTB_TextChanged(object sender, EventArgs e)
    {
        if(nameTB.Text == "")
            datagridview1.DataSource = visibleDataTable;
        else
        {
            browseDataTable.DefaultView.RowFilter = "name LIKE '%" + nameTB.Text + "%'";
            datagridview1.DataSource = browseDataTable;   
        }
    }

Не сработало, потому что обычно по-прежнему слишком много товаров до 3 букв, а после каждой буквы 5-секундная задержка, после 3-4 букв - мгновенная.

Идеальное решение было быбыть примерно таким:

private void nameTB_TextChanged(object sender, EventArgs e)
{
    browseDataTable.DefaultView.RowFilter = "name LIKE '%" + nameTB.Text + "%'";
    browseDataTable.AsEnumerable().Take(100).CopyToDataTable(visibleDataTable, LoadOption.OverwriteChanges);
}

Но это тоже не работает, потому что 'Take (100)' всегда берет первые 100 из DataTable, отфильтрованные или нет.

(Ограничение самого запроса также не будет работать, потому что тогда на каждом письме будет запрос, который с сетевым сервером увеличит перегрузку сети и будет медленным, особеннодействительно, если пользователь начинает писать быстро)

1 Ответ

0 голосов
/ 14 октября 2019

Оказывается, ответ проще, чем я думал

private void nameTB_TextChanged(object sender, EventArgs e)
{
    browseDataTable.DefaultView.RowFilter = "name LIKE '%" + nameTB.Text + "%'";
    visibleDataTable = browseDataTable.DefaultView.ToTable().AsEnumerable().Take(100).CopyToDataTable();
    datagridview1.DataSource = visibleDataTable;
}

Это фильтрует по буквам, которые я хотел, и ограничивает строки до 100, что делает весь процесс мгновенным.

...