Вы заметили, что отображаемые строки можно сортировать самыми разными способами, если последовательно нажимать мышью заголовки всех столбцов элемента DataGridView? Эта внешняя сортировка никак не влияет на то значение, которое дает выражение rows[0][0]. Оно всего лишь выбирает значение, расположенное в нулевом столбце той строки DataTable, индекс которой записан в элементе rows[0]. Нулевой столбец соответствует полю ID и мы узнаем ключ первой из найденных записей. Если строки DataGridView в данный момент отсортированы по этому столбцу, то результат поиска будет показан (маркирован) правильно, если по другому — нет.
В процессе отбора строк из DataTable не учитывается факт внешней сортировки, так как эта структура расположена в памяти и не сортируется при нажатии на заголовки DataGridView. Напомним, что компонент DataGridView лишь отображает объекты. Ниже приводится одно из решений этой проблемы, но оно далеко от оптимального.
void Find()
{
string what = Trim(comboFind.Text);
if (what == "")
return;
DataRow[] rows = ds.Tables[0].Select("Name LIKE '" + what + "*'");
if (rows.Length == 0)
{
// Здесь ваш код
// Показываем метку "Not Found"
return;
}
// Здесь ваш код Прячем метку "Not Found"
// Запоминаем искомую строку в списке
int i; // Ищем индекс строки по факту совпадения реальной ячейки с полем найденной строки
for (i = 0; i< studsGrid.Rows.Count; i++)
{
if (studsGrid.Rows[i].Cells[1].Value.ToString() == rows[0]["Name"].ToString())
break;
}
studsGrid.CurrentCell = studsGrid.Rows[i].Cells[1]; // Выделяем первую из найденных строк
}
Приведенная версия метода Find пытается учесть факт сортировки на экране. Внимательно рассмотрите выражение: studsGrid.Rows[i].Cells[1].Value.ToString(). Отметьте, что его синтаксис сильно отличается от выраженияrows[0]["Name"].ToString().
¨ Первое возвращает строковое значение того объекта, который в данный момент времени (с учетом сортировки) расположен в ячейке DataGridView с координатами (i,1).
¨ Второе выражение содержит результат поиска и отбора в DataTable, то есть в памяти, а не на экране. Оно не учитывает факт внешней сортировки.
Мы ищем совпадение этих объектов и тем самым учитываем факт сортировки. Характерно, что выражение rows[0]["Name"] имеет тип object, а выражение studsGrid.Rows[i].Cells[1] — ссылка на объект типа DataGridViewTextBoxCell. Поэтому их нельзя сравнивать без предварительного приведения к строковому типу.
Анализ поведения приложения в режиме поиска, наводит на мысль о том, что целесообразно производить поиск не в таблице, поддерживаемой классом DataTable, а непосредственно в компоненте DataGridView. Хотелось бы сделать поиск более удобным. Например, продолжить его со строки, следующей за той, которая в данный момент содержит фокус. Процедуру поиска обычно зацикливают так, чтобы при прохождении всего списка можно было повторить ее сначала. Мы сделаем это без назойливого напоминания о том, что очередной цикл поиска закончился. Это можно выполнить, например, так.
¨ Ввести в класс формы вспомогательные переменные:
DataGridViewCell activeCell, foundCell;
bool bFindNext; // Надо ли производить сдвиг при продолжении поиска
string findWhat;
¨ Произвести их инициализацию в конструкторе класса:
// Здесь ваш код
¨ Изменить алгоритм метода Find и разработать метод FindNext:
void Find()
{
int row = 0, col = 0;
if (activeCell != null)
{
row = activeCell.RowIndex;
col = activeCell.ColumnIndex;
}
string text = Trim(comboFind.Text); // Искомый текст
if (findWhat != text)
findWhat = text;
if (bFindNext || activeCell == foundCell)
row++;
if (FindNext(row, col))
{
sNotFound.Visible = false;
if (!comboFind.Items.Contains(comboFind.Text))
comboFind.Items.Add(comboFind.Text);
bFindNext = true;
}
else
sNotFound.Visible = true;
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.